diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 060a71d..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# NOTE! Don't add files that are generated in specific
-# subdirectories here. Add them in the ".gitignore" file
-# in that subdirectory instead.
-#
-# Normal rules
-#
-.*
-*.o
-*.a
-*.s
-*.ko
-*.so
-*.mod.c
-*.i
-*.lst
-*.symtypes
-
-#
-# Top-level generic files
-#
-tags
-TAGS
-vmlinux*
-System.map
-Module.symvers
-
-#
-# Generated include files
-#
-include/asm
-include/asm-*/asm-offsets.h
-include/config
-include/linux/autoconf.h
-include/linux/compile.h
-include/linux/version.h
-include/linux/utsrelease.h
-
-# stgit generated dirs
-patches-*
-
-# quilt's files
-patches
-series
-
-# cscope files
-cscope.*
diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt
index d6788da..7fbb6ff 100644
--- a/Documentation/filesystems/relay.txt
+++ b/Documentation/filesystems/relay.txt
@@ -157,7 +157,7 @@ TBD(curr. line MT:/API/)
   channel management functions:
 
     relay_open(base_filename, parent, subbuf_size, n_subbufs,
-               callbacks)
+               callbacks, private_data)
     relay_close(chan)
     relay_flush(chan)
     relay_reset(chan)
@@ -251,7 +251,7 @@ static struct rchan_callbacks relay_callbacks =
 
 And an example relay_open() invocation using them:
 
-  chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks);
+  chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks, NULL);
 
 If the create_buf_file() callback fails, or isn't defined, channel
 creation and thus relay_open() will fail.
@@ -289,6 +289,11 @@ they use the proper locking for such a buffer, either by wrapping
 writes in a spinlock, or by copying a write function from relay.h and
 creating a local version that internally does the proper locking.
 
+The private_data passed into relay_open() allows clients to associate
+user-defined data with a channel, and is immediately available
+(including in create_buf_file()) via chan->private_data or
+buf->chan->private_data.
+
 Channel 'modes'
 ---------------
 
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 5a8bd5b..bfee52d 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -193,3 +193,5 @@ Code	Seq#	Include File		Comments
 					<mailto:thomas@winischhofer.net>
 0xF4	00-1F	video/mbxfb.h		mbxfb
 					<mailto:raph@8d.com>
+0xF5	00-3F	ltt/ltt-tracer.h        LTTng
+					<mailto:mathieu.desnoyers@polymtl.ca>
diff --git a/Documentation/local_ops.txt b/Documentation/local_ops.txt
new file mode 100644
index 0000000..bd854b3
--- /dev/null
+++ b/Documentation/local_ops.txt
@@ -0,0 +1,163 @@
+	     Semantics and Behavior of Local Atomic Operations
+
+			    Mathieu Desnoyers
+
+
+	This document explains the purpose of the local atomic operations, how
+to implement them for any given architecture and shows how they can be used
+properly. It also stresses on the precautions that must be taken when reading
+those local variables across CPUs when the order of memory writes matters.
+
+
+
+* Purpose of local atomic operations
+
+Local atomic operations are meant to provide fast and highly reentrant per CPU
+counters. They minimize the performance cost of standard atomic operations by
+removing the LOCK prefix and memory barriers normally required to synchronize
+across CPUs.
+
+Having fast per CPU atomic counters is interesting in many cases : it does not
+require disabling interrupts to protect from interrupt handlers and it permits
+coherent counters in NMI handlers. It is especially useful for tracing purposes
+and for various performance monitoring counters.
+
+Local atomic operations only guarantee variable modification atomicity wrt the
+CPU which owns the data. Therefore, care must taken to make sure that only one
+CPU writes to the local_t data. This is done by using per cpu data and making
+sure that we modify it from within a preemption safe context. It is however
+permitted to read local_t data from any CPU : it will then appear to be written
+out of order wrt other memory writes on the owner CPU.
+
+
+* Implementation for a given architecture
+
+It can be done by slightly modifying the standard atomic operations : only
+their UP variant must be kept. It typically means removing LOCK prefix (on
+i386 and x86_64) and any SMP sychronization barrier. If the architecture does
+not have a different behavior between SMP and UP, including asm-generic/local.h
+in your archtecture's local.h is sufficient.
+
+The local_t type is defined as an opaque signed long by embedding an
+atomic_long_t inside a structure. This is made so a cast from this type to a
+long fails. The definition looks like :
+
+typedef struct { atomic_long_t a; } local_t;
+
+
+* How to use local atomic operations
+
+#include <linux/percpu.h>
+#include <asm/local.h>
+
+static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+
+* Counting
+
+Counting is done on all the bits of a signed long.
+
+In preemptible context, use get_cpu_var() and put_cpu_var() around local atomic
+operations : it makes sure that preemption is disabled around write access to
+the per cpu variable. For instance :
+
+	local_inc(&get_cpu_var(counters));
+	put_cpu_var(counters);
+
+If you are already in a preemption-safe context, you can directly use 
+__get_cpu_var() instead.
+
+	local_inc(&__get_cpu_var(counters));
+
+
+
+* Reading the counters
+
+Those local counters can be read from foreign CPUs to sum the count. Note that
+the data seen by local_read across CPUs must be considered to be out of order
+relatively to other memory writes happening on the CPU that owns the data.
+
+	long sum = 0;
+	for_each_online_cpu(cpu)
+		sum += local_read(&per_cpu(counters, cpu));
+
+If you want to use a remote local_read to synchronize access to a resource
+between CPUs, explicit smp_wmb() and smp_rmb() memory barriers must be used
+respectively on the writer and the reader CPUs. It would be the case if you use
+the local_t variable as a counter of bytes written in a buffer : there should
+be a smp_wmb() between the buffer write and the counter increment and also a
+smp_rmb() between the counter read and the buffer read.
+
+
+Here is a sample module which implements a basic per cpu counter using local.h.
+
+--- BEGIN ---
+/* test-local.c
+ *
+ * Sample module for local.h usage.
+ */
+
+
+#include <asm/local.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+
+static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
+
+static struct timer_list test_timer;
+
+/* IPI called on each CPU. */
+static void test_each(void *info)
+{
+	/* Increment the counter from a non preemptible context */
+	printk("Increment on cpu %d\n", smp_processor_id());
+	local_inc(&__get_cpu_var(counters));
+
+	/* This is what incrementing the variable would look like within a
+	 * preemptible context (it disables preemption) :
+	 *
+	 * local_inc(&get_cpu_var(counters));
+	 * put_cpu_var(counters);
+	 */
+}
+
+static void do_test_timer(unsigned long data)
+{
+	int cpu;
+
+	/* Increment the counters */
+	on_each_cpu(test_each, NULL, 0, 1);
+	/* Read all the counters */
+	printk("Counters read from CPU %d\n", smp_processor_id());
+	for_each_online_cpu(cpu) {
+		printk("Read : CPU %d, count %ld\n", cpu,
+			local_read(&per_cpu(counters, cpu)));
+	}
+	del_timer(&test_timer);
+	test_timer.expires = jiffies + 1000;
+	add_timer(&test_timer);
+}
+
+static int __init test_init(void)
+{
+	/* initialize the timer that will increment the counter */
+	init_timer(&test_timer);
+	test_timer.function = do_test_timer;
+	test_timer.expires = jiffies + 1;
+	add_timer(&test_timer);
+
+	return 0;
+}
+
+static void __exit test_exit(void)
+{
+	del_timer_sync(&test_timer);
+}
+
+module_init(test_init);
+module_exit(test_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Local Atomic Ops");
+--- END ---
diff --git a/Documentation/marker.txt b/Documentation/marker.txt
new file mode 100644
index 0000000..58a655a
--- /dev/null
+++ b/Documentation/marker.txt
@@ -0,0 +1,266 @@
+ 	             Using the Linux Kernel Markers
+
+			    Mathieu Desnoyers
+
+
+	This document introduces to markers and discusses its purpose. It
+shows some usage examples of the Linux Kernel Markers : how to insert markers
+within the kernel and how to connect probes to a marker. Finally, it has some
+probe module examples. This is what connects to a marker.
+
+
+* Purpose of markers
+
+A marker placed in your code provides a hook to a function (probe) that
+you can provide at runtime. A marker can be "on" (a probe is connected to it)
+or "off" (no probe is attached). An "off" marker has no effect. When turned on,
+the function you provide is called each time the marker is executed in the
+execution context of the caller. When the function provided ends its execution,
+it returns to the caller (marker site).
+
+You can put markers at important locations in the code. They act as
+lightweight hooks that can pass an arbitrary number of parameters,
+described in a printk-like format string, to a function whenever the marker
+code is reached.
+
+They can be used for tracing (LTTng, LKET over SystemTAP), overall performance
+accounting (SystemTAP). They could also be used to implement
+efficient hooks for SELinux or any other subsystem that would have this
+kind of need.
+
+Using the markers for system audit (SELinux) would require to pass a
+variable by address that would be later checked by the marked routine.
+
+
+* Usage
+
+In order to use the macro MARK, you should include linux/marker.h.
+
+#include <linux/marker.h>
+
+Add, in your code :
+
+MARK(subsystem_event, "%d %s", someint, somestring);
+Where :
+- subsystem_event is an identifier unique to your event
+    - subsystem is the name of your subsystem.
+    - event is the name of the event to mark.
+- "%d %s" is the formatted string for the serializer.
+- someint is an integer.
+- somestring is a char pointer.
+
+Connecting a function (probe) to a marker is done by providing a probe
+(function to call) for the specific marker through marker_set_probe(). It will
+automatically connect the function and enable the marker site. Removing a probe
+is done through marker_remove_probe(). Probe removal is preempt safe because
+preemption is disabled around the probe call. See the "Probe example" section
+below for a sample probe module.
+
+The marker mechanism supports multiple instances of the same marker.
+Markers can be put in inline functions, inlined static functions and
+unrolled loops.
+
+Note : It is safe to put markers within preempt-safe code : preempt_enable()
+will not call the scheduler due to the tests in preempt_schedule().
+
+
+* Optimization for a given architecture
+
+You will find, in asm-*/marker.h, optimisations for given architectures
+(currently i386 and powerpc). They use a load immediate instead of a data load,
+which saves a data cache hit, but also requires cross CPU code modification. In
+order to support embedded systems which use read-only memory for their code, the
+optimization can be disabled through menu options.
+
+The MF_* flags can be used to control the type of marker. See the
+include/marker.h header for the list of flags. They can be specified as the
+first parameter of the _MARK() macro, such as the following example which is
+safe with respect to lockdep.c (useful for marking lockdep.c and printk
+functions).
+
+_MARK(_MF_DEFAULT | ~_MF_LOCKDEP, subsystem_eventb, MARK_NOARGS);
+
+Another example is to specify that a specific marker must never call printk :
+_MARK(_MF_DEFAULT | ~_MF_PRINTK, subsystem_eventc,
+  "%d %s", someint, somestring,);
+
+Flag compatibility is checked before connecting the probe to the marker : the
+right flags must be given to _marker_set_enable().
+
+
+* Probe example
+
+You can build the kernel modules, probe-example.ko and marker-example.ko,
+using the following Makefile:
+------------------------------ CUT -------------------------------------
+obj-m := probe-example.o marker-example.o
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+default:
+	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+clean:
+	rm -f *.mod.c *.ko *.o
+------------------------------ CUT -------------------------------------
+/* probe-example.c
+ *
+ * Connects a two functions to marker call sites.
+ *
+ * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <asm/atomic.h>
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct probe_data))
+
+struct probe_data {
+	const char *name;
+	const char *format;
+	marker_probe_func *probe_func;
+};
+
+void probe_subsystem_event(const struct __mark_marker_c *mdata,
+		const char *format, ...)
+{
+	va_list ap;
+	/* Declare args */
+	unsigned int value;
+	const char *mystr;
+
+	/* Assign args */
+	va_start(ap, format);
+	value = va_arg(ap, typeof(value));
+	mystr = va_arg(ap, typeof(mystr));
+
+	/* Call printk */
+	printk("Value %u, string %s\n", value, mystr);
+
+	/* or count, check rights, serialize data in a buffer */
+
+	va_end(ap);
+}
+
+atomic_t eventb_count = ATOMIC_INIT(0);
+
+void probe_subsystem_eventb(const struct __mark_marker_c *mdata,
+	const char *format, ...)
+{
+	/* Increment counter */
+	atomic_inc(&eventb_count);
+}
+
+static struct probe_data probe_array[] =
+{
+	{	.name = "subsystem_event",
+		.format = "%d %s",
+		.probe_func = probe_subsystem_event },
+	{	.name = "subsystem_eventb",
+		.format = MARK_NOARGS,
+		.probe_func = probe_subsystem_eventb },
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				probe_array[eID].probe_func, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "Unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	printk("Number of event b : %u\n", atomic_read(&eventb_count));
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("SUBSYSTEM Probe");
+------------------------------ CUT -------------------------------------
+/* marker-example.c
+ *
+ * Executes a marker when /proc/marker-example is opened.
+ *
+ * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+
+struct proc_dir_entry *pentry_example = NULL;
+
+static int my_open(struct inode *inode, struct file *file)
+{
+	int i;
+
+	MARK(subsystem_event, "%d %s", 123, "example string");
+	for (i=0; i<10; i++) {
+		MARK(subsystem_eventb, MARK_NOARGS);
+	}
+	return -EPERM;
+}
+
+static struct file_operations mark_ops = {
+	.open = my_open,
+};
+
+static int example_init(void)
+{
+	printk(KERN_ALERT "example init\n");
+	pentry_example = create_proc_entry("marker-example", 0444, NULL);
+	if (pentry_example)
+		pentry_example->proc_fops = &mark_ops;
+	else
+		return -EPERM;
+	return 0;
+}
+
+static void example_exit(void)
+{
+	printk(KERN_ALERT "example exit\n");
+	remove_proc_entry("marker-example", NULL);
+}
+
+module_init(example_init)
+module_exit(example_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit example");
+------------------------------ CUT -------------------------------------
+Sequence of operations : (as root)
+make
+insmod marker-example.ko
+insmod probe-example.ko
+  (it is important to load the probe after the marked code)
+cat /proc/marker-example (returns an expected error)
+rmmod marker-example probe-example
+dmesg
+------------------------------ CUT -------------------------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index 0ad8803..63003a7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2070,6 +2070,13 @@ W:	http://lsm.immunix.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
 S:	Supported
 
+LINUX TRACE TOOLKIT NEXT GENERATION
+P:	Mathieu Desnoyers
+M:	mathieu.desnoyers@polymtl.ca
+L:	ltt-dev@listserv.shafik.org
+W:	http://ltt.polymtl.ca
+S:	Maintained
+
 LM83 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
 M:	khali@linux-fr.org
diff --git a/Makefile b/Makefile
index 7e2750f..ca7b1fc 100644
--- a/Makefile
+++ b/Makefile
@@ -490,6 +490,10 @@ endif
 
 include $(srctree)/arch/$(ARCH)/Makefile
 
+ifdef CONFIG_IPIPE_TRACE_MCOUNT
+CFLAGS          += -pg
+endif
+
 ifdef CONFIG_FRAME_POINTER
 CFLAGS		+= -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
 else
@@ -553,7 +557,7 @@ export mod_strip_cmd
 
 
 ifeq ($(KBUILD_EXTMOD),)
-core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/ ltt/
 
 vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
 		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 84caf50..4823971 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -638,6 +638,14 @@ source "fs/Kconfig"
 
 source "arch/alpha/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/alpha/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 76bf071..ecadd05 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -88,6 +88,7 @@ SECTIONS
   _data = .;
   .data : {					/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
   }
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6783c2e..0813af0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,14 @@ source "fs/Kconfig"
 
 source "arch/arm/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/arm/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index f7598cb..e540c02 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -1,13 +1,13 @@
 /*
- *  linux/arch/arm/kernel/calls.S
+ * linux/arch/arm/kernel/calls.S
  *
- *  Copyright (C) 1995-2005 Russell King
+ * Copyright (C) 1995-2005 Russell King
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  This file is included thrice in entry-common.S
+ * This file is included thrice in entry-common.S
  */
 /* 0 */		CALL(sys_restart_syscall)
 		CALL(sys_exit)
@@ -356,6 +356,8 @@
 		CALL(sys_move_pages)
 /* 345 */	CALL(sys_getcpu)
 		CALL(sys_ni_syscall)		/* eventually epoll_pwait */
+		CALL(sys_ltt_trace_generic)
+		CALL(sys_ltt_register_generic)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 6f5e7c5..fbc03db 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -78,8 +78,8 @@ ENTRY(ret_from_fork)
 	get_thread_info tsk
 	ldr	r1, [tsk, #TI_FLAGS]		@ check for syscall tracing
 	mov	why, #1
-	tst	r1, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
-	beq	ret_slow_syscall
+	tst	r1, #_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	beq	ret_slow_syscall		@ are we tracing syscalls?
 	mov	r1, sp
 	mov	r0, #1				@ trace exit [IP = 1]
 	bl	syscall_trace
@@ -198,8 +198,8 @@ ENTRY(vector_swi)
 #endif
 
 	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
-	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
-	bne	__sys_trace
+	tst	ip, #_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT 
+	bne	__sys_trace			@ are we tracing syscalls?
 
 	cmp	scno, #NR_syscalls		@ check upper syscall limit
 	adr	lr, ret_fast_syscall		@ return address
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index a9e8f7e..13647de 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -399,6 +399,7 @@ asm(	".section .text\n"
 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 	struct pt_regs regs;
+	long pid;
 
 	memset(&regs, 0, sizeof(regs));
 
@@ -408,7 +409,10 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 	regs.ARM_pc = (unsigned long)kernel_thread_helper;
 	regs.ARM_cpsr = SVC_MODE;
 
-	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+	pid = do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+
+	MARK(kernel_arch_kthread_create, "%ld %p", pid, fn);
+	return pid;
 }
 EXPORT_SYMBOL(kernel_thread);
 
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 9254ba2..a44e7d8 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -812,6 +812,12 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
 {
 	unsigned long ip;
 
+	if (!why)
+		MARK(kernel_arch_syscall_entry, "%d %ld",
+			scno, instruction_pointer(regs));
+	else
+		MARK(kernel_arch_syscall_exit, MARK_NOARGS);
+
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return scno;
 	if (!(current->ptrace & PT_PTRACED))
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 3d4fcbc..62196e8 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -161,6 +161,8 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third,
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
+	MARK(kernel_arch_ipc_call, "%u %d", call, first);
+
 	switch (call) {
 	case SEMOP:
 		return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 3c8cdcf..e7d90d8 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -34,6 +34,7 @@
 #include <asm/leds.h>
 #include <asm/thread_info.h>
 #include <asm/mach/time.h>
+#include <asm/ltt.h>
 
 /*
  * Our system timer.
@@ -344,6 +345,9 @@ void timer_tick(void)
 	do_leds();
 	do_set_rtc();
 	do_timer(1);
+#ifdef CONFIG_LTT
+	ltt_reset_timestamp();
+#endif
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 9089156..6cd311b 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -246,7 +246,13 @@ void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
 		current->thread.error_code = err;
 		current->thread.trap_no = trap;
 
+		MARK(kernel_arch_trap_entry, "%ld %ld", current->thread.trap_no,
+			instruction_pointer(regs));
+		
 		force_sig_info(info->si_signo, info, current);
+
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
+		
 	} else {
 		die(str, regs, err);
 	}
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index a8fa75e..a384212 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -150,6 +150,7 @@ SECTIONS
 		 * and the usual data section
 		 */
 		*(.data)
+		EXTRA_RWDATA
 		CONSTRUCTORS
 
 		_edata = .;
@@ -161,7 +162,7 @@ SECTIONS
 		*(COMMON)
 		_end = .;
 	}
-					/* Stabs debugging sections.	*/
+
 	.stab 0 : { *(.stab) }
 	.stabstr 0 : { *(.stabstr) }
 	.stab.excl 0 : { *(.stab.excl) }
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index 74eba8b..f7f6533 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -240,6 +240,14 @@ source "drivers/misc/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/arm26/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
index ca61ec8..abdaee0 100644
--- a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
+++ b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
@@ -110,6 +110,7 @@ SECTIONS
 		 * and the usual data section
 		 */
 		*(.data)
+		EXTRA_RWDATA
 		CONSTRUCTORS
 
 		*(.init.data)
@@ -121,8 +122,9 @@ SECTIONS
 		__bss_start = .;	/* BSS				*/
 		*(.bss)
 		*(COMMON)
-		_end = . ;
 	}
+
+	_end = . ;
 					/* Stabs debugging sections.	*/
 	.stab 0 : { *(.stab) }
 	.stabstr 0 : { *(.stabstr) }
diff --git a/arch/arm26/kernel/vmlinux-arm26.lds.in b/arch/arm26/kernel/vmlinux-arm26.lds.in
index d1d3418..ecd9d2b 100644
--- a/arch/arm26/kernel/vmlinux-arm26.lds.in
+++ b/arch/arm26/kernel/vmlinux-arm26.lds.in
@@ -105,6 +105,7 @@ SECTIONS
 		 * and the usual data section
 		 */
 		*(.data)
+		EXTRA_RWDATA
 		CONSTRUCTORS
 
 		_edata = .;
@@ -114,8 +115,9 @@ SECTIONS
 		__bss_start = .;	/* BSS				*/
 		*(.bss)
 		*(COMMON)
-		_end = . ;
 	}
+
+	_end = . ;
 					/* Stabs debugging sections.	*/
 	.stab 0 : { *(.stab) }
 	.stabstr 0 : { *(.stabstr) }
diff --git a/arch/avr32/Kconfig.debug b/arch/avr32/Kconfig.debug
index 64ace00..e1192b4 100644
--- a/arch/avr32/Kconfig.debug
+++ b/arch/avr32/Kconfig.debug
@@ -6,6 +6,9 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
+menu "Instrumentation Support"
+	depends on EXPERIMENTAL
+
 config KPROBES
 	bool "Kprobes"
 	depends on DEBUG_KERNEL
@@ -16,4 +19,11 @@ config KPROBES
           for kernel debugging, non-intrusive instrumentation and testing.
           If in doubt, say "N".
 
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
+
 endmenu
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index f2e81cd..58a14c8 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -306,14 +306,12 @@ asmlinkage void do_debug_priv(struct pt_regs *regs)
 	if (likely(ds & DS_SSS)) {
 		extern void itlb_miss(void);
 		extern void tlb_miss_common(void);
-		struct thread_info *ti;
 
 		dc = __mfdr(DBGREG_DC);
 		dc &= ~DC_SS;
 		__mtdr(DBGREG_DC, dc);
 
-		ti = current_thread_info();
-		ti->flags |= _TIF_BREAKPOINT;
+		set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
 
 		/* The TLB miss handlers don't check thread flags */
 		if ((regs->pc >= (unsigned long)&itlb_miss)
@@ -328,7 +326,7 @@ asmlinkage void do_debug_priv(struct pt_regs *regs)
 		 * single step.
 		 */
 		if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR)
-			ti->flags |= TIF_SINGLE_STEP;
+			set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
 	} else {
 		panic("Unable to handle debug trap at pc = %08lx\n",
 		      regs->pc);
diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
index 5c4424e..c77b104 100644
--- a/arch/avr32/kernel/vmlinux.lds.c
+++ b/arch/avr32/kernel/vmlinux.lds.c
@@ -103,12 +103,12 @@ SECTIONS
 		/* And the rest... */
 		*(.data.rel*)
 		*(.data)
+		EXTRA_RWDATA
 		CONSTRUCTORS
-
+		
 		_edata = .;
 	}
 
-
 	. = ALIGN(8);
 	.bss    	: AT(ADDR(.bss) - LOAD_OFFSET) {
 		__bss_start = .;
@@ -116,9 +116,10 @@ SECTIONS
 		*(COMMON)
 		. = ALIGN(8);
 		__bss_stop = .;
-		_end = .;
 	}
 
+	_end = .;
+
 	/* When something in the kernel is NOT compiled as a module, the module
 	 * cleanup code and data are put into these segments. Both can then be
 	 * thrown away, as cleanup code is never called unless it's a module.
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 3474309..57f5bf8 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -191,6 +191,14 @@ source "sound/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/cris/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S
index 689729a..cc5827b 100644
--- a/arch/cris/arch-v10/vmlinux.lds.S
+++ b/arch/cris/arch-v10/vmlinux.lds.S
@@ -45,6 +45,7 @@ SECTIONS
 	__Sdata = . ;
 	.data : {                     /* Data */
 		*(.data)
+		EXTRA_RWDATA
 	}
 	__edata = . ;                 /* End of data section */
 	_edata = . ;
diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S
index 472d4b3..934850d 100644
--- a/arch/cris/arch-v32/vmlinux.lds.S
+++ b/arch/cris/arch-v32/vmlinux.lds.S
@@ -50,6 +50,7 @@ SECTIONS
 	__Sdata = . ;
 	.data : {                     /* Data */
 		*(.data)
+		EXTRA_RWDATA
 	}
 	__edata = . ;		/* End of data section. */
 	_edata = . ;
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 7561d7b..1a350e5 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -375,6 +375,14 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/frv/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 9c1fb12..2f3d844 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -134,6 +134,7 @@ SECTIONS
   .data : {			/* Data */
 	*(.data .data.*)
 	*(.exit.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	}
 
@@ -155,6 +156,7 @@ SECTIONS
   .bss.stack	: { *(.bss) }
 
   __bss_stop = .;
+
   _end = . ;
   . = ALIGN(PAGE_SIZE);
   __kernel_image_end = .;
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 34a84bc..963b47f 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -205,6 +205,14 @@ endmenu
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/h8300/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index f05288b..b955341 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -105,7 +105,9 @@ SECTIONS
 	. = ALIGN(0x4) ;
 		*(.data)
 	. = ALIGN(0x4) ;
-		*(.data.*)	
+		*(.data.*)
+	. = ALIGN(0x4) ;
+	EXTRA_RWDATA
 
 	. = ALIGN(0x4) ;
 	___init_begin = .;
@@ -134,6 +136,7 @@ SECTIONS
 	___init_end = .;
 	__edata = . ;
 	}
+
 #if defined(CONFIG_RAMKERNEL)
 	SECURITY_INIT
 #endif
@@ -147,9 +150,10 @@ SECTIONS
 		*(COMMON)
 	. = ALIGN(0x4) ;
 	__ebss = . ;
+	}
+
 	__end = . ;
 	__ramstart = .;
-	}
 	/DISCARD/ : {
 		*(.exitcall.exit)
 	}
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 0dfee81..aff1a5c 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1210,6 +1210,11 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
 endmenu
 
 source "arch/i386/Kconfig.debug"
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 1e8988e..890576b 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_VM86)		+= vm86.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_K8_NB)		+= k8.o
+obj-$(CONFIG_MARKERS_ENABLE_OPTIMIZATION)	+= marker.o
 
 # Make sure this is linked after any other paravirt_ops structs: see head.S
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o
diff --git a/arch/i386/kernel/marker.c b/arch/i386/kernel/marker.c
new file mode 100644
index 0000000..5c0925b
--- /dev/null
+++ b/arch/i386/kernel/marker.c
@@ -0,0 +1,98 @@
+/* marker.c
+ *
+ * Erratum 49 fix for Intel PIII and higher.
+ *
+ * Permits marker activation by XMC with correct serialization.
+ *
+ * Reentrant for NMI and trap handler instrumentation. Permits XMC to a
+ * location that has preemption enabled because it involves no temporary or
+ * reused data structure.
+ *
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ */
+
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/preempt.h>
+#include <linux/smp.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <asm/cacheflush.h>
+#include <asm/kdebug.h>
+
+#define BREAKPOINT_INSTRUCTION  0xcc
+#define BREAKPOINT_INS_LEN 1
+
+static DEFINE_MUTEX(mark_mutex);
+static long target_eip = 0;
+
+static void mark_synchronize_core(void *info)
+{
+	sync_core();	/* use cpuid to stop speculative execution */
+}
+
+/* We simply skip the 2 bytes load immediate here, leaving the register in an
+ * undefined state. We don't care about the content (0 or !0), because we are
+ * changing the value 0->1 or 1->0. This small window of undefined value
+ * doesn't matter.
+ */
+static int mark_notifier(struct notifier_block *nb,
+	unsigned long val, void *data)
+{
+	enum die_val die_val = (enum die_val) val;
+	struct die_args *args = (struct die_args *)data;
+	
+	if (!args->regs || user_mode_vm(args->regs))
+		return NOTIFY_DONE;
+
+	if (die_val == DIE_INT3	&& args->regs->eip == target_eip) {
+		args->regs->eip += 1; /* Skip the next byte of load immediate */
+		return NOTIFY_STOP;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block mark_notify = {
+	.notifier_call = mark_notifier,
+	.priority = 0x7fffffff,	/* we need to be notified first */
+};
+
+int marker_optimized_set_enable(void *address, char enable)
+{
+	char saved_byte;
+	int ret;
+	char *dest = address;
+
+	if (!(enable ^ dest[1])) /* Must be a state change 0<->1 to execute */
+		return 0;
+
+	mutex_lock(&mark_mutex);
+	target_eip = (long)address + BREAKPOINT_INS_LEN;
+	/* register_die_notifier has memory barriers */
+	register_die_notifier(&mark_notify);
+	saved_byte = *dest;
+	*dest = BREAKPOINT_INSTRUCTION;
+	wmb();
+	/* Execute serializing instruction on each CPU.
+	 * Acts as a memory barrier. */
+	ret = on_each_cpu(mark_synchronize_core, NULL, 1, 1);
+	BUG_ON(ret != 0);
+
+	dest[1] = enable;
+	wmb();
+	*dest = saved_byte;
+		/* Wait for all int3 handlers to end
+		   (interrupts are disabled in int3).
+		   This CPU is clearly not in a int3 handler
+		   (not preemptible).
+		   synchronize_sched has memory barriers */
+	synchronize_sched();
+	unregister_die_notifier(&mark_notify);
+	/* unregister_die_notifier has memory barriers */
+	target_eip = 0;
+	mutex_unlock(&mark_mutex);
+	flush_icache_range(address, size);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(marker_optimized_set_enable);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index c641056..966545a 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -332,6 +332,7 @@ extern void kernel_thread_helper(void);
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	struct pt_regs regs;
+	long pid;
 
 	memset(&regs, 0, sizeof(regs));
 
@@ -347,7 +348,10 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 	regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
 
 	/* Ok, create the new process.. */
-	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+	pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED,
+			0, &regs, 0, NULL, NULL);
+	MARK(kernel_arch_kthread_create, "%ld %p", pid, fn);
+	return pid;
 }
 EXPORT_SYMBOL(kernel_thread);
 
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index af8aabe..a09c9a3 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -660,6 +660,15 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit)
 	 */
 	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
 	int ret = 0;
+	
+	if (!entryexit) {
+		MARK(kernel_arch_syscall_entry, "%d %ld", 
+			(int)regs->orig_eax, instruction_pointer(regs));
+		MARK(stack_arch_syscall_dump_kernel_stack, MARK_NOARGS, regs);
+		MARK(stack_arch_syscall_dump_process32_stack,
+			MARK_NOARGS, regs);
+	} else
+		MARK(kernel_arch_syscall_exit, MARK_NOARGS);
 
 	/* do the secure computing check first */
 	if (!entryexit)
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
index 4048397..6b8379c 100644
--- a/arch/i386/kernel/sys_i386.c
+++ b/arch/i386/kernel/sys_i386.c
@@ -130,6 +130,8 @@ asmlinkage int sys_ipc (uint call, int first, int second,
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
+	MARK(kernel_arch_ipc_call, "%u %d", call, first);
+
 	switch (call) {
 	case SEMOP:
 		return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 2697e92..49af72e 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -319,3 +319,5 @@ ENTRY(sys_call_table)
 	.long sys_move_pages
 	.long sys_getcpu
 	.long sys_epoll_pwait
+	.long sys_ltt_trace_generic	/* 320 */
+	.long sys_ltt_register_generic
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index c505b16..9d36c89 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -57,6 +57,7 @@
 #include <asm/processor.h>
 #include <asm/timer.h>
 #include <asm/time.h>
+#include <asm/ltt.h>
 
 #include "mach_time.h"
 
@@ -186,6 +187,10 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
 	}
 #endif
 
+#ifdef CONFIG_LTT
+	ltt_reset_timestamp();
+#endif //CONFIG_LTT
+
 	do_timer_interrupt_hook();
 
 
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 0efad8a..56de33a 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -31,6 +31,7 @@
 #include <linux/uaccess.h>
 #include <linux/nmi.h>
 #include <linux/bug.h>
+#include <linux/ltt-core.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -422,6 +423,11 @@ void die(const char * str, struct pt_regs * regs, long err)
 #endif
 		if (nl)
 			printk("\n");
+#ifdef CONFIG_LTT
+		printk("LTT NESTING LEVEL : %u ",
+				ltt_nesting[smp_processor_id()]);
+		printk("\n");
+#endif
 		if (notify_die(DIE_OOPS, str, regs, err,
 					current->thread.trap_no, SIGSEGV) !=
 				NOTIFY_STOP) {
@@ -476,6 +482,9 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = trapnr;
 
+	MARK(kernel_arch_trap_entry, "%d %ld", trapnr,
+		instruction_pointer(regs));
+
 	if (regs->eflags & VM_MASK) {
 		if (vm86)
 			goto vm86_trap;
@@ -490,20 +499,22 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
 			force_sig_info(signr, info, tsk);
 		else
 			force_sig(signr, tsk);
-		return;
+		goto end;
 	}
 
 	kernel_trap: {
 		if (!fixup_exception(regs))
 			die(str, regs, error_code);
-		return;
+		goto end;
 	}
 
 	vm86_trap: {
 		int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
 		if (ret) goto trap_signal;
-		return;
+		goto end;
 	}
+end:
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 #define DO_ERROR(trapnr, signr, str, name) \
@@ -611,12 +622,16 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
 
 	current->thread.error_code = error_code;
 	current->thread.trap_no = 13;
+	MARK(kernel_arch_trap_entry, "%d %ld", 13, instruction_pointer(regs));
 	force_sig(SIGSEGV, current);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 	return;
 
 gp_in_vm86:
 	local_irq_enable();
+	MARK(kernel_arch_trap_entry, "%d %ld", 13, instruction_pointer(regs));
 	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 	return;
 
 gp_in_kernel:
@@ -720,26 +735,30 @@ static __kprobes void default_do_nmi(struct pt_regs * regs)
 	/* Only the BSP gets external NMIs from the system.  */
 	if (!smp_processor_id())
 		reason = get_nmi_reason();
+
+	MARK(kernel_arch_trap_entry, "%d %ld", 2, instruction_pointer(regs));
+	MARK(stack_arch_nmi_dump_kernel_stack, MARK_NOARGS, regs);
  
 	if (!(reason & 0xc0)) {
 		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-							== NOTIFY_STOP)
-			return;
+							== NOTIFY_STOP) {
+			goto end;
+		}
 #ifdef CONFIG_X86_LOCAL_APIC
 		/*
 		 * Ok, so this is none of the documented NMI sources,
 		 * so it must be the NMI watchdog.
 		 */
 		if (nmi_watchdog_tick(regs, reason))
-			return;
+			goto end;
 		if (!do_nmi_callback(regs, smp_processor_id()))
 #endif
 			unknown_nmi_error(reason, regs);
 
-		return;
+		goto end;
 	}
 	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-		return;
+		goto end;
 	if (reason & 0x80)
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
@@ -749,6 +768,8 @@ static __kprobes void default_do_nmi(struct pt_regs * regs)
 	 * as it's edge-triggered.
 	 */
 	reassert_nmi();
+end:
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
@@ -842,7 +863,9 @@ fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
 	}
 
 	/* Ok, finally something we can handle */
+	MARK(kernel_arch_trap_entry, "%d %ld", 1, instruction_pointer(regs));
 	send_sigtrap(tsk, regs, error_code);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 
 	/* Disable additional traps. They'll be re-enabled when
 	 * the signal is delivered.
@@ -852,7 +875,9 @@ clear_dr7:
 	return;
 
 debug_vm86:
+	MARK(kernel_arch_trap_entry, "%d %ld", 1, instruction_pointer(regs));
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 	return;
 
 clear_TF_reenable:
@@ -1006,10 +1031,12 @@ fastcall void do_simd_coprocessor_error(struct pt_regs * regs,
 fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
 					  long error_code)
 {
+	MARK(kernel_arch_trap_entry, "%d %ld", 16, instruction_pointer(regs));
 #if 0
 	/* No need to warn about this any longer. */
 	printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 fastcall unsigned long patch_espfix_desc(unsigned long uesp,
@@ -1061,8 +1088,10 @@ asmlinkage void math_emulate(long arg)
 {
 	printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n");
 	printk(KERN_EMERG "killing %s.\n",current->comm);
+	MARK(kernel_arch_trap_entry, "%d %ld", 7, 0);
 	force_sig(SIGFPE,current);
 	schedule();
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 #endif /* CONFIG_MATH_EMULATION */
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index a53c8b1..9034207 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -71,6 +71,7 @@ SECTIONS
   . = ALIGN(4096);
   .data : AT(ADDR(.data) - LOAD_OFFSET) {	/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	} :data
 
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index aaaa4d2..9e7a8e6 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -450,16 +450,21 @@ good_area:
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
+	MARK(kernel_arch_trap_entry, "%d %ld", 14, instruction_pointer(regs));
 	switch (handle_mm_fault(mm, vma, address, write)) {
 		case VM_FAULT_MINOR:
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			tsk->min_flt++;
 			break;
 		case VM_FAULT_MAJOR:
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			tsk->maj_flt++;
 			break;
 		case VM_FAULT_SIGBUS:
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			goto do_sigbus;
 		case VM_FAULT_OOM:
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			goto out_of_memory;
 		default:
 			BUG();
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index fcacfe2..79b5029 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -564,6 +564,11 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
 endmenu
 
 source "arch/ia64/Kconfig.debug"
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index d6083a0..2a8cef7 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -204,7 +204,7 @@ SECTIONS
 
   data : { } :data
   .data : AT(ADDR(.data) - LOAD_OFFSET)
-	{ *(.data) *(.data1) *(.gnu.linkonce.d*) CONSTRUCTORS }
+	{ *(.data) *(.data1) *(.gnu.linkonce.d*) EXTRA_RWDATA CONSTRUCTORS }
 
   . = ALIGN(16);	/* gp must be 16-byte aligned for exc. table */
   .got : AT(ADDR(.got) - LOAD_OFFSET)
@@ -221,7 +221,7 @@ SECTIONS
 	{ *(.sbss) *(.scommon) }
   .bss : AT(ADDR(.bss) - LOAD_OFFSET)
 	{ *(.bss) *(COMMON) }
-
+ 
   _end = .;
 
   code : { } :code
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index f383dab..f557005 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -394,6 +394,14 @@ source "fs/Kconfig"
 
 source "arch/m32r/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/m32r/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 358b9ce..f62518f 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -48,6 +48,7 @@ SECTIONS
 	*(.spu)
 	*(.spi)
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	}
 
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 70a577c..1b3813d 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -660,6 +660,14 @@ endmenu
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/m68k/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index d279445..c0706e8 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -29,6 +29,7 @@ SECTIONS
 
   .data : {			/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	}
 
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index 8c7eccb..63bd38d 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -24,6 +24,7 @@ SECTIONS
 
   .data : {			/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	. = ALIGN(16);		/* Exception table */
 	__start___ex_table = .;
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 25993c2..e197d93 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -669,6 +669,14 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/m68knommu/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 2b2a10d..93b2372 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -124,6 +124,7 @@ SECTIONS {
 		. = ALIGN(4);
 		_sdata = . ;
 		*(.data)
+		EXTRA_RWDATA
 		. = ALIGN(8192) ;
 		*(.data.init_task)
 		_edata = . ;
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index f978627..38ce8d7 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -80,7 +80,7 @@ ENTRY(system_call)
 	movel	%sp,%d1			/* get thread_info pointer */
 	andl	#-THREAD_SIZE,%d1
 	movel	%d1,%a2
-	btst    #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
+	btst	#(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
 	jne	do_trace
 	cmpl	#NR_syscalls,%d0
 	jcc	badsys
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index bbd386f..bfb9e98 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2082,6 +2082,14 @@ source "fs/Kconfig"
 
 source "arch/mips/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/mips/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index ec8209f..0d99d76 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -256,6 +256,7 @@ ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
 long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 	struct pt_regs regs;
+	long pid;
 
 	memset(&regs, 0, sizeof(regs));
 
@@ -271,7 +272,10 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 #endif
 
 	/* Ok, create the new process.. */
-	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+	pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED,
+			0, &regs, 0, NULL, NULL);
+	MARK(kernel_arch_kthread_create, "%ld %p", pid, fn);
+	return pid;
 }
 
 /*
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 258d74f..1659281 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -473,6 +473,12 @@ static inline int audit_arch(void)
  */
 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
+	if (!entryexit)
+		MARK(kernel_arch_syscall_entry, "%d %ld", 
+			(int)regs->regs[2], instruction_pointer(regs));
+	else
+		MARK(kernel_arch_syscall_exit, MARK_NOARGS);
+
 	if (unlikely(current->audit_context) && entryexit)
 		audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]),
 		                   regs->regs[2]);
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 7c0b393..8368f46 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -656,6 +656,8 @@ einval:	li	v0, -EINVAL
 	sys	sys_kexec_load		4
 	sys	sys_getcpu		3
 	sys	sys_epoll_pwait		6
+	sys	sys_ltt_trace_generic	6
+	sys	sys_ltt_register_generic	2	/* 4315 */
 	.endm
 
 	/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index e569b84..4eb41f9 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -471,3 +471,5 @@ sys_call_table:
 	PTR	sys_kexec_load			/* 5270 */
 	PTR	sys_getcpu
 	PTR	sys_epoll_pwait
+	PTR	sys_ltt_trace_generic
+	PTR	sys_ltt_register_generic
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index a7bff2a..8030910 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -395,5 +395,7 @@ EXPORT(sysn32_call_table)
 	PTR	compat_sys_set_robust_list
 	PTR	compat_sys_get_robust_list
 	PTR	compat_sys_kexec_load
-	PTR	sys_getcpu
+	PTR	sys_getcpu			/* 6275 */
 	PTR	sys_epoll_pwait
+	PTR	sys_ltt_trace_generic
+	PTR	sys_ltt_register_generic
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index e91379c..cefca6e 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -519,4 +519,6 @@ sys_call_table:
 	PTR	compat_sys_kexec_load
 	PTR	sys_getcpu
 	PTR	sys_epoll_pwait
+	PTR	sys_ltt_trace_generic
+	PTR	sys_ltt_register_generic	/* 4315 */
 	.size	sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 26e1a7e..5d46907 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -314,6 +314,8 @@ asmlinkage int sys_ipc (unsigned int call, int first, int second,
 
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
+	
+	MARK(kernel_arch_ipc_call, "%u %d", call, first);
 
 	switch (call) {
 	case SEMOP:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 8aa544f..a53402f 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -455,6 +455,7 @@ EXPORT_SYMBOL(rtc_lock);
 EXPORT_SYMBOL(to_tm);
 EXPORT_SYMBOL(rtc_mips_set_time);
 EXPORT_SYMBOL(rtc_mips_get_time);
+EXPORT_SYMBOL(mips_hpt_frequency);
 
 unsigned long long sched_clock(void)
 {
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 2a932ca..13ba637 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -288,7 +288,7 @@ void show_regs(struct pt_regs *regs)
 
 	printk("Cause : %08x\n", cause);
 
-	cause = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
+	cause = CAUSE_EXCCODE(cause);
 	if (1 <= cause && cause <= 5)
 		printk("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
 
@@ -608,6 +608,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
 	die_if_kernel("FP exception in kernel code", regs);
 
+	MARK(kernel_arch_trap_entry, "%d %ld", CAUSE_EXCCODE(regs->cp0_cause),
+		instruction_pointer(regs));
 	if (fcr31 & FPU_CSR_UNI_X) {
 		int sig;
 
@@ -776,16 +778,23 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
 	die_if_kernel("do_cpu invoked from kernel context!", regs);
 
+	MARK(kernel_arch_trap_entry, "%d %ld", CAUSE_EXCCODE(regs->cp0_cause),
+		instruction_pointer(regs));
+
 	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
 
 	switch (cpid) {
 	case 0:
 		if (!cpu_has_llsc)
-			if (!simulate_llsc(regs))
+			if (!simulate_llsc(regs)) {
+				MARK(kernel_arch_trap_exit, MARK_NOARGS);
 				return;
+			}
 
-		if (!simulate_rdhwr(regs))
+		if (!simulate_rdhwr(regs)) {
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			return;
+		}
 
 		break;
 
@@ -840,7 +849,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 			}
 #endif /* CONFIG_MIPS_MT_FPAFF */
 		}
-
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return;
 
 	case 2:
@@ -850,6 +859,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 	}
 
 	force_sig(SIGILL, current);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 asmlinkage void do_mdmx(struct pt_regs *regs)
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 7e7d548..21e4759 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -496,14 +496,19 @@ asmlinkage void do_ade(struct pt_regs *regs)
 	unsigned int __user *pc;
 	mm_segment_t seg;
 
+	MARK(kernel_arch_trap_entry, "%d %ld", CAUSE_EXCCODE(regs->cp0_cause),
+		instruction_pointer(regs));
+
 	/*
 	 * Address errors may be deliberately induced by the FPU emulator to
 	 * retake control of the CPU after executing the instruction in the
 	 * delay slot of an emulated branch.
 	 */
 	/* Terminate if exception was recognized as a delay slot return */
-	if (do_dsemulret(regs))
+	if (do_dsemulret(regs)) {
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return;
+	}
 
 	/* Otherwise handle as normal */
 
@@ -537,6 +542,8 @@ asmlinkage void do_ade(struct pt_regs *regs)
 	}
 	set_fs(seg);
 
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
+
 	return;
 
 sigbus:
@@ -546,4 +553,6 @@ sigbus:
 	/*
 	 * XXX On return from the signal handler we should advance the epc
 	 */
+
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index cecff24..6de58ea 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -64,6 +64,8 @@ SECTIONS
 
     *(.data)
 
+    EXTRA_RWDATA
+
     CONSTRUCTORS
   }
   _gp = . + 0x8000;
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 6f90e7e..5cb4286 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -103,16 +103,22 @@ survive:
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
+        MARK(kernel_arch_trap_entry, "%d %ld", CAUSE_EXCCODE(regs->cp0_cause),
+		instruction_pointer(regs));
 	switch (handle_mm_fault(mm, vma, address, write)) {
 	case VM_FAULT_MINOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		tsk->min_flt++;
 		break;
 	case VM_FAULT_MAJOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		tsk->maj_flt++;
 		break;
 	case VM_FAULT_SIGBUS:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		goto do_sigbus;
 	case VM_FAULT_OOM:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		goto out_of_memory;
 	default:
 		BUG();
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 0f9ff61..84301e9 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -263,6 +263,14 @@ source "fs/Kconfig"
 
 source "arch/parisc/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/parisc/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 7b943b4..988558b 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -90,6 +90,7 @@ SECTIONS
   . = ALIGN(L1_CACHE_BYTES);
   .data : {			/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	}
 
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d6abe49..0513904 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -705,6 +705,8 @@ source arch/powerpc/platforms/ps3/Kconfig
 
 menu "Kernel options"
 
+source "kernel/ipipe/Kconfig"
+
 config HIGHMEM
 	bool "High memory support"
 	depends on PPC32
@@ -1189,6 +1191,11 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+  
 endmenu
 
 source "arch/powerpc/Kconfig.debug"
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 98392fb..524dc29 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -27,6 +27,14 @@ BOOTCFLAGS	:= $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
 		   $(shell $(CROSS32CC) -print-file-name=include) -fPIC
 BOOTAFLAGS	:= -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
 
+ifdef CONFIG_IPIPE_TRACE
+# do not trace the boot loader
+nullstring :=
+space      := $(nullstring) # end of the line
+pg_flag     = $(nullstring) -pg # end of the line
+BOOTCFLAGS     := $(subst ${pg_flag},${space},${BOOTCFLAGS})
+endif
+
 ifeq ($(call cc-option-yn, -fstack-protector),y)
 BOOTCFLAGS	+= -fno-stack-protector
 endif
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index d2ded19..6149be7 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -38,6 +38,9 @@ obj-$(CONFIG_TAU)		+= tau_6xx.o
 obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
 obj32-$(CONFIG_MODULES)		+= module_32.o
 
+obj-$(CONFIG_IPIPE)		+= ipipe.o
+obj-$(CONFIG_IPIPE_TRACE_MCOUNT)	+= mcount.o
+
 ifeq ($(CONFIG_PPC_MERGE),y)
 
 extra-$(CONFIG_PPC_STD_MMU)	:= head_32.o
@@ -92,3 +95,4 @@ obj-$(CONFIG_PPC64)		+= $(obj64-y)
 
 extra-$(CONFIG_PPC_FPU)		+= fpu.o
 extra-$(CONFIG_PPC64)		+= entry_64.o
+obj-$(CONFIG_MARKERS_ENABLE_OPTIMIZATION)	+= marker.o
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index b742013..fa5752a 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1218,7 +1218,7 @@ static struct cpu_spec cpu_specs[] = {
 #endif /* CONFIG_PPC32 */
 };
 
-struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr)
+notrace struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr)
 {
 	struct cpu_spec *s = cpu_specs;
 	struct cpu_spec **cur = &cur_cpu_spec;
@@ -1247,7 +1247,7 @@ struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr)
 	return NULL;
 }
 
-void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
+notrace void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 {
 	struct fixup_entry {
 		unsigned long	mask;
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c03e829..7e7224e 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -132,8 +132,23 @@ transfer_to_handler:
          * check for stack overflow
          */
 	lwz	r9,THREAD_INFO-THREAD(r12)
+#ifdef CONFIG_IPIPE
+	/* Allow for private kernel-based stacks: those must not cause
+	the stack overflow detection to trigger when some activity has
+	been preempted over them. We just check if the kernel stack is
+	not treading on the memory area ranging from
+	&current->thread_info to &current->thread, which is coarser
+	than the vanilla implementation, but likely sensitive enough
+	to catch overflows soon enough though.*/
+	addi	r12,r9,THREAD
+	cmplw	0,r1,r9
+	cmplw	1,r1,r12
+	crand	1,1,4
+	bgt-	stack_ovf		/* if r9 < r1 < r9+THREAD */
+#else /* CONFIG_IPIPE */
 	cmplw	r1,r9			/* if r1 <= current->thread_info */
 	ble-	stack_ovf		/* then the kernel stack overflowed */
+#endif /* CONFIG_IPIPE */
 5:
 #ifdef CONFIG_6xx
 	tophys(r9,r9)			/* check local flags */
@@ -198,6 +213,21 @@ _GLOBAL(DoSyscall)
 	lwz	r11,_CCR(r1)	/* Clear SO bit in CR */
 	rlwinm	r11,r11,0,4,2
 	stw	r11,_CCR(r1)
+#ifdef CONFIG_IPIPE
+	addi	r3,r1,GPR0
+	bl	__ipipe_syscall_root
+	cmpwi	r3,0
+	lwz	r3,GPR3(r1)
+	lwz	r0,GPR0(r1)
+	lwz	r4,GPR4(r1)
+	lwz	r5,GPR5(r1)
+	lwz	r6,GPR6(r1)
+	lwz	r7,GPR7(r1)
+	lwz	r8,GPR8(r1)
+	lwz	r9,GPR9(r1)
+	bgt	.ipipe_end_syscall
+	blt	ret_from_syscall
+#endif /* CONFIG_IPIPE */
 #ifdef SHOW_SYSCALLS
 	bl	do_show_syscall
 #endif /* SHOW_SYSCALLS */
@@ -260,11 +290,34 @@ syscall_exit_cont:
 	SYNC
 	RFI
 
+#ifdef CONFIG_IPIPE
+.ipipe_end_syscall:
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
+	SYNC
+	MTMSRD(r10)
+	b syscall_exit_cont
+#endif /* CONFIG_IPIPE */
+
 66:	li	r3,-ENOSYS
 	b	ret_from_syscall
 
 	.globl	ret_from_fork
 ret_from_fork:
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	stwu	r1,-4(r1)
+	stw	r3,0(r1)
+	lis	r3,(0x80000000)@h
+	ori	r3,r3,(0x80000000)@l
+	bl	ipipe_trace_end
+	lwz	r3,0(r1)
+	addi	r1,r1,4
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
+	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)
+#endif /* CONFIG_IPIPE */		
 	REST_NVGPRS(r1)
 	bl	schedule_tail
 	li	r3,0
@@ -630,6 +683,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
+	mfmsr	r10		/* this is used later, might be messed */
+        beq- restore
+#endif /* CONFIG_IPIPE */
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r0,r3,MSR_PR
 	beq	resume_kernel
@@ -653,6 +712,12 @@ restore_user:
 #ifdef CONFIG_PREEMPT
 	b	restore
 
+#ifdef CONFIG_IPIPE
+#define PREEMPT_SCHEDULE_IRQ	__ipipe_preempt_schedule_irq
+#else
+#define PREEMPT_SCHEDULE_IRQ	preempt_schedule_irq
+#endif
+
 /* N.B. the only way to get here is from the beq following ret_from_except. */
 resume_kernel:
 	/* check current_thread_info->preempt_count */
@@ -665,7 +730,7 @@ resume_kernel:
 	beq+	restore
 	andi.	r0,r3,MSR_EE	/* interrupts off? */
 	beq	restore		/* don't schedule if so */
-1:	bl	preempt_schedule_irq
+1:	bl	PREEMPT_SCHEDULE_IRQ
 	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
 	lwz	r3,TI_FLAGS(r9)
 	andi.	r0,r3,_TIF_NEED_RESCHED
@@ -929,6 +994,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
 
 	.comm	ee_restarts,4
 
+#ifdef CONFIG_IPIPE
+_GLOBAL(__ipipe_ret_from_except)
+        cmpwi   r3, 0
+        bne+ ret_from_except
+        b restore
+#endif /* CONFIG_IPIPE */
+
 /*
  * PROM code for specific machines follows.  Put it
  * here so it's easy to add arch-specific sections later.
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 821e152..0eabdf0 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -94,7 +94,17 @@ _GLOBAL(load_up_fpu)
  * Enables the FPU for use in the kernel on return.
  */
 _GLOBAL(giveup_fpu)
+#ifdef CONFIG_IPIPE
+	mfmsr	r6
+#ifdef CONFIG_PPC64	
+	rldicl	r5,r6,48,1		/* clear MSR_EE */
+	rotldi	r5,r5,16
+#else
+	rlwinm	r5,r6,0,17,15		/* clear MSR_EE */
+#endif	
+#else	
 	mfmsr	r5
+#endif	
 	ori	r5,r5,MSR_FP
 	SYNC_601
 	ISYNC_601
@@ -102,7 +112,7 @@ _GLOBAL(giveup_fpu)
 	SYNC_601
 	isync
 	PPC_LCMPI	0,r3,0
-	beqlr-				/* if no previous owner, done */
+	beq-	2f			/* if no previous owner, done */
 	addi	r3,r3,THREAD	        /* want THREAD of task */
 	PPC_LL	r5,PT_REGS(r3)
 	PPC_LCMPI	0,r5,0
@@ -120,6 +130,18 @@ _GLOBAL(giveup_fpu)
 	LOAD_REG_ADDRBASE(r4,last_task_used_math)
 	PPC_STL	r5,ADDROFF(last_task_used_math)(r4)
 #endif /* CONFIG_SMP */
+2:
+#ifdef CONFIG_IPIPE		/* restore interrupt state */
+	andi.	r6,r6,MSR_EE
+	beqlr
+	mfmsr	r5
+	ori	r5,r5,MSR_EE
+	SYNC_601
+	ISYNC_601
+	MTMSRD(r5)
+	SYNC_601
+	isync
+#endif
 	blr
 
 /*
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 9417cf5..7da03a5 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -329,6 +329,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)
@@ -418,7 +424,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
@@ -450,7 +460,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
 	EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
 
 /* 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, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index accb39d..8af68f8 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -426,8 +426,11 @@ interrupt_base:
 	/* Instruction Storage Interrupt */
 	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 --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_4xx.S
index adc7f80..9d96de7 100644
--- a/arch/powerpc/kernel/head_4xx.S
+++ b/arch/powerpc/kernel/head_4xx.S
@@ -228,6 +228,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 --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 901be47..c393c7b 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -187,6 +187,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)
@@ -238,7 +244,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
@@ -259,7 +269,11 @@ Alignment:
 	EXCEPTION(0x800, FPUnavailable, unknown_exception, 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, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index 8536e76..8a2ae17 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -187,6 +187,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)
@@ -345,6 +351,15 @@ label:
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
 	EXC_XFER_STD(0x0700, program_check_exception)
 
+#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;					      \
@@ -352,6 +367,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 --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 66877bd..1846753 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -526,7 +526,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 --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 8994af3..5a80ada 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -58,6 +58,7 @@ void cpu_idle(void)
 	while (1) {
 		while (!need_resched() && !cpu_should_die()) {
 			ppc64_runlatch_off();
+			ipipe_suspend_domain();
 
 			if (ppc_md.power_save) {
 				clear_thread_flag(TIF_POLLING_NRFLAG);
@@ -66,13 +67,13 @@ void cpu_idle(void)
 				 * is ordered w.r.t. need_resched() test.
 				 */
 				smp_mb();
-				local_irq_disable();
+				local_irq_disable_hw();
 
 				/* check again after disabling irqs */
 				if (!need_resched() && !cpu_should_die())
 					ppc_md.power_save();
 
-				local_irq_enable();
+				local_irq_enable_hw();
 				set_thread_flag(TIF_POLLING_NRFLAG);
 
 			} else {
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c
index 34ae114..10ea724 100644
--- a/arch/powerpc/kernel/io.c
+++ b/arch/powerpc/kernel/io.c
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(_outsl_ns);
 
 #define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0)
 
-void _memset_io(volatile void __iomem *addr, int c, unsigned long n)
+notrace void _memset_io(volatile void __iomem *addr, int c, unsigned long n)
 {
 	void *p = (void __force *)addr;
 	u32 lc = c;
diff --git a/arch/powerpc/kernel/ipipe.c b/arch/powerpc/kernel/ipipe.c
new file mode 100644
index 0000000..543a8b3
--- /dev/null
+++ b/arch/powerpc/kernel/ipipe.c
@@ -0,0 +1,779 @@
+/* -*- linux-c -*-
+ * linux/arch/powerpc/kernel/ipipe.c
+ *
+ * Copyright (C) 2005 Heikki Lindholm (PPC64 port).
+ * Copyright (C) 2004 Wolfgang Grandegger (Adeos/ppc port over 2.4).
+ * Copyright (C) 2002-2007 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 PowerPC 32/64bit.
+ */
+
+#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 <linux/kernel_stat.h>
+#include <asm/reg.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/unistd.h>
+#include <asm/machdep.h>
+#include <asm/atomic.h>
+#include <asm/hardirq.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). */
+DEFINE_PER_CPU(unsigned long long, __ipipe_decr_next);
+
+static void __ipipe_do_IRQ(unsigned irq, void *cookie);
+
+static void __ipipe_do_timer(unsigned irq, void *cookie);
+
+DEFINE_PER_CPU(struct pt_regs, __ipipe_tick_regs);
+
+#ifdef CONFIG_SMP
+
+#include <asm/mpic.h>	/* We currently need a MPIC to support SMP. */
+
+static cpumask_t __ipipe_cpu_sync_map;
+
+static cpumask_t __ipipe_cpu_lock_map;
+
+static ipipe_spinlock_t __ipipe_cpu_barrier = IPIPE_SPIN_LOCK_UNLOCKED;
+
+static atomic_t __ipipe_critical_count = ATOMIC_INIT(0);
+
+static void (*__ipipe_cpu_sync) (void);
+
+static DEFINE_PER_CPU(struct ipipe_ipi_struct, ipipe_ipi_message);
+
+unsigned int __ipipe_ipi_irq = NR_IRQS + 1; /* dummy value */
+
+/* Always called with hw interrupts off. */
+
+void __ipipe_do_critical_sync(unsigned irq, void *cookie)
+{
+	cpu_set(ipipe_processor_id(), __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(&__ipipe_cpu_barrier);
+
+	/* Got it. Now get out. */
+
+	if (__ipipe_cpu_sync)
+		/* Call the sync routine if any. */
+		__ipipe_cpu_sync();
+
+	spin_unlock(&__ipipe_cpu_barrier);
+
+	cpu_clear(ipipe_processor_id(), __ipipe_cpu_sync_map);
+}
+
+void __ipipe_hook_critical_ipi(struct ipipe_domain *ipd)
+{
+	ipd->irqs[IPIPE_CRITICAL_IPI].acknowledge = NULL;
+	ipd->irqs[IPIPE_CRITICAL_IPI].handler = &__ipipe_do_critical_sync;
+	ipd->irqs[IPIPE_CRITICAL_IPI].cookie = NULL;
+	/* Immediately handle in the current domain but *never* pass */
+	ipd->irqs[IPIPE_CRITICAL_IPI].control =
+		IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK;
+}
+
+void __ipipe_register_ipi(unsigned int irq)
+{
+	__ipipe_ipi_irq = irq;
+	mb();
+} 
+
+static void __ipipe_ipi_demux(int irq)
+{
+	int ipi, cpu = ipipe_processor_id();
+	
+	__ipipe_ack_irq(irq);
+
+	kstat_cpu(cpu).irqs[irq]++;
+
+	while (per_cpu(ipipe_ipi_message.value, cpu) & IPIPE_MSG_IPI_MASK) {
+		for (ipi = IPIPE_MSG_CRITICAL_IPI; ipi <= IPIPE_MSG_SERVICE_IPI4; ++ipi) {
+			if (test_and_clear_bit(ipi, &per_cpu(ipipe_ipi_message.value, cpu))) {
+				mb();
+				__ipipe_handle_irq(ipi + IPIPE_MSG_IPI_OFFSET, NULL);
+			}
+		}
+	}
+
+	__ipipe_end_irq(irq);
+}
+
+cpumask_t __ipipe_set_irq_affinity(unsigned irq, cpumask_t cpumask)
+{
+	cpumask_t oldmask = irq_desc[irq].affinity;
+
+	if (irq_desc[irq].chip->set_affinity == NULL)
+		return CPU_MASK_NONE;
+
+	if (cpus_empty(cpumask))
+		return oldmask; /* Return mask value -- no change. */
+
+	cpus_and(cpumask,cpumask,cpu_online_map);
+
+	if (cpus_empty(cpumask))
+		return CPU_MASK_NONE;	/* Error -- bad mask value or non-routable IRQ. */
+
+	irq_desc[irq].chip->set_affinity(irq,cpumask);
+
+	return oldmask;
+}
+
+int __ipipe_send_ipi(unsigned ipi, cpumask_t cpumask)
+{
+	extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask);
+	unsigned long flags;
+	int cpu;
+
+	local_irq_save_hw(flags);
+
+	ipi -= IPIPE_MSG_IPI_OFFSET;
+	for_each_online_cpu(cpu) {
+		if (cpu_isset(cpu, cpumask))
+			set_bit(ipi, &per_cpu(ipipe_ipi_message.value, cpu));
+	}
+	mb();	 
+	
+	if (!cpus_empty(cpumask))
+#ifdef CONFIG_MPIC
+		mpic_send_ipi(0x2, cpus_addr(cpumask)[0]);
+#else
+#error "We have only MPIC support here!"
+#endif
+	local_irq_restore_hw(flags);
+
+	return 0;
+}
+
+void __ipipe_stall_root(void)
+{
+	set_bit_safe(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+}
+
+unsigned long __ipipe_test_and_stall_root(void)
+{
+	return test_and_set_bit_safe(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+}
+
+unsigned long __ipipe_test_root(void)
+{
+	return test_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+}
+
+#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 (likely(num_online_cpus() > 1)) {
+		/* We might be running a SMP-kernel on a UP box... */
+		int cpu = ipipe_processor_id();
+		cpumask_t lock_map;
+		cpumask_t others;
+
+		if (!cpu_test_and_set(cpu, __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 < cpu);
+			}
+
+			spin_lock(&__ipipe_cpu_barrier);
+
+			__ipipe_cpu_sync = syncfn;
+
+			/* Send the sync IPI to all processors but the current one. */
+			cpus_setall(others);
+			cpu_clear(ipipe_processor_id(), others);
+			__ipipe_send_ipi(IPIPE_CRITICAL_IPI, others);
+
+			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 (likely(num_online_cpus() > 1)) {
+		/* We might be running a SMP-kernel on a UP box... */
+		if (atomic_dec_and_test(&__ipipe_critical_count)) {
+			spin_unlock(&__ipipe_cpu_barrier);
+
+			while (!cpus_empty(__ipipe_cpu_sync_map))
+				cpu_relax();
+
+			cpu_clear(ipipe_processor_id(), __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 int virq;
+
+	/*
+	 * Allocate a virtual IRQ for the decrementer trap early to
+	 * get it mapped to IPIPE_VIRQ_BASE
+	 */
+
+	virq = ipipe_alloc_virq();
+
+	if (virq != IPIPE_TIMER_VIRQ)
+		panic("I-pipe: cannot reserve timer virq #%d (got #%d)",
+		      IPIPE_TIMER_VIRQ, virq);
+
+	__ipipe_decr_ticks = tb_ticks_per_jiffy;
+#ifdef CONFIG_SMP
+	virq = ipipe_alloc_virq();
+	if (virq != IPIPE_CRITICAL_IPI)
+		panic("I-pipe: cannot reserve critical IPI virq #%d (got #%d)",
+		      IPIPE_CRITICAL_IPI, virq);
+	virq = ipipe_alloc_virq();
+	if (virq != IPIPE_SERVICE_IPI0)
+		panic("I-pipe: cannot reserve service IPI 0 virq #%d (got #%d)",
+		      IPIPE_SERVICE_IPI0, virq);
+	virq = ipipe_alloc_virq();
+	if (virq != IPIPE_SERVICE_IPI1)
+		panic("I-pipe: cannot reserve service IPI 1 virq #%d (got #%d)",
+		      IPIPE_SERVICE_IPI1, virq);
+	virq = ipipe_alloc_virq();
+	if (virq != IPIPE_SERVICE_IPI2)
+		panic("I-pipe: cannot reserve service IPI 2 virq #%d (got #%d)",
+		      IPIPE_SERVICE_IPI2, virq);
+	virq = ipipe_alloc_virq();
+	if (virq != IPIPE_SERVICE_IPI3)
+		panic("I-pipe: cannot reserve service IPI 3 virq #%d (got #%d)",
+		      IPIPE_SERVICE_IPI3, virq);
+	virq = ipipe_alloc_virq();
+	if (virq != IPIPE_SERVICE_IPI4)
+		panic("I-pipe: cannot reserve service IPI 4 virq #%d (got #%d)",
+		      IPIPE_SERVICE_IPI4, virq);
+#endif
+}
+
+int __ipipe_ack_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	desc->ipipe_ack(irq, desc);
+	return 1;
+}
+
+void __ipipe_end_irq(unsigned irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	desc->ipipe_end(irq, desc);
+}
+
+void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
+{
+	irq_desc[irq].status &= ~IRQ_DISABLED;
+}
+
+static void __ipipe_enable_sync(void)
+{
+	__raw_get_cpu_var(__ipipe_decr_next) = __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,
+				     &__ipipe_do_IRQ, NULL,
+				     &__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,
+			     &__ipipe_do_timer, NULL,
+			     NULL, IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
+
+	__raw_get_cpu_var(__ipipe_decr_next) = __ipipe_read_timebase() + get_dec();
+
+	ipipe_critical_exit(flags);
+}
+
+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;
+}
+
+/*
+ * ipipe_trigger_irq() -- Push the interrupt at front of the pipeline
+ * just like if it has been actually received from a hw source. Also
+ * works for virtual interrupts.
+ */
+int ipipe_trigger_irq(unsigned irq)
+{
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS ||
+	    (ipipe_virtual_irq_p(irq)
+	     && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map)))
+		return -EINVAL;
+
+	local_irq_save_hw(flags);
+
+	__ipipe_handle_irq(irq, NULL);
+
+	local_irq_restore_hw(flags);
+
+	return 1;
+}
+
+/*
+ * __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic
+ * interrupt protection log is maintained here for each domain. Hw
+ * interrupts are off on entry.
+ */
+void __ipipe_handle_irq(int irq, struct pt_regs *regs)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *head, *pos;
+	int m_ack;
+
+	m_ack = (regs == NULL);	/* Software-triggered IRQs do not need
+				 * any ack. */
+	if (unlikely(irq >= IPIPE_NR_IRQS)) {
+		printk(KERN_ERR "I-pipe: spurious interrupt %d\n", irq);
+		return;
+	}
+
+	this_domain = ipipe_current_domain;
+
+	if (unlikely(test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control)))
+		head = &this_domain->p_link;
+	else {
+		head = __ipipe_pipeline.next;
+		next_domain = list_entry(head, struct ipipe_domain, p_link);
+		if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) {
+			if (!m_ack && next_domain->irqs[irq].acknowledge != NULL)
+				next_domain->irqs[irq].acknowledge(irq);
+			if (likely(__ipipe_dispatch_wired(next_domain, irq)))
+			    goto finalize;
+			return;
+		}
+	}
+
+	/* Ack the interrupt. */
+
+	pos = head;
+
+	while (pos != &__ipipe_pipeline) {
+		next_domain = list_entry(pos, struct ipipe_domain, p_link);
+		/*
+		 * For each domain handling the incoming IRQ, mark it as
+		 * pending in its log.
+		 */
+		if (test_bit(IPIPE_HANDLE_FLAG, &next_domain->irqs[irq].control)) {
+			/*
+			 * Domains that handle this IRQ are polled for
+			 * acknowledging it by decreasing priority order. The
+			 * interrupt must be made pending _first_ in the
+			 * domain's status flags before the PIC is unlocked.
+			 */
+			__ipipe_set_irq_pending(next_domain, irq);
+
+			if (next_domain->irqs[irq].acknowledge != NULL && !m_ack)
+				m_ack = next_domain->irqs[irq].acknowledge(irq);
+		}
+
+		/*
+		 * If the domain does not want the IRQ to be passed down the
+		 * interrupt pipe, exit the loop now.
+		 */
+		if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control))
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+
+finalize:
+	/*
+	 * Now walk the pipeline, yielding control to the highest
+	 * priority domain that has pending interrupt(s) or
+	 * immediately to the current domain if the interrupt has been
+	 * marked as 'sticky'. This search does not go beyond the
+	 * current domain in the pipeline.
+	 */
+
+	__ipipe_walk_pipeline(head);
+}
+
+int __ipipe_grab_irq(struct pt_regs *regs)
+{
+	extern int ppc_spurious_interrupts;
+	int irq;
+
+	irq = ppc_md.get_irq();
+
+	if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
+		ipipe_trace_irq_entry(irq);
+#ifdef CONFIG_SMP
+		/* check for cascaded I-pipe IPIs */
+		if (irq == __ipipe_ipi_irq)
+			__ipipe_ipi_demux(irq);
+		else
+#endif /* CONFIG_SMP */
+			__ipipe_handle_irq(irq, regs);
+		ipipe_trace_irq_exit(irq);
+	} else if (irq != NO_IRQ_IGNORE)
+		ppc_spurious_interrupts++;
+
+	if (ipipe_root_domain_p) {
+#ifdef CONFIG_PPC_970_NAP
+		struct thread_info *ti = current_thread_info();
+		/* Emulate the napping check when 100% sure we do run
+		 * over the root context. */
+		if (test_and_clear_bit(TLF_NAPPING, &ti->local_flags))
+			regs->nip = regs->link;
+#endif
+		if (!test_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status)))
+			return 1;
+	}
+
+	return 0;
+}
+
+static void __ipipe_do_IRQ(unsigned irq, void *cookie)
+{
+	struct pt_regs *old_regs;
+#ifdef CONFIG_IRQSTACKS
+	struct thread_info *curtp, *irqtp;
+#endif
+
+	/* Provide a valid register frame, even if not the exact one. */
+	old_regs = set_irq_regs(&__raw_get_cpu_var(__ipipe_tick_regs));
+
+	irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+	/* Debugging check for stack overflow: is there less than 2KB free? */
+	{
+		long sp;
+
+		sp = __get_SP() & (THREAD_SIZE-1);
+
+		if (unlikely(sp < (sizeof(struct thread_info) + 2048))) {
+			printk("do_IRQ: stack overflow: %ld\n",
+				sp - sizeof(struct thread_info));
+			dump_stack();
+		}
+	}
+#endif
+
+#ifdef CONFIG_IRQSTACKS
+		/* Switch to the irq stack to handle this */
+		curtp = current_thread_info();
+		irqtp = hardirq_ctx[smp_processor_id()];
+		if (curtp != irqtp) {
+			struct irq_desc *desc = irq_desc + irq;
+			void *handler = desc->handle_irq;
+			if (handler == NULL)
+				handler = &__do_IRQ;
+			irqtp->task = curtp->task;
+			irqtp->flags = 0;
+			call_handle_irq(irq, desc, irqtp, handler);
+			irqtp->task = NULL;
+			if (irqtp->flags)
+				set_bits(irqtp->flags, &curtp->flags);
+		} else
+#endif
+			generic_handle_irq(irq);
+
+	irq_exit();
+
+	set_irq_regs(old_regs);
+}
+
+static void __ipipe_do_timer(unsigned irq, void *cookie)
+{
+	timer_interrupt(&__raw_get_cpu_var(__ipipe_tick_regs));
+}
+
+int __ipipe_grab_timer(struct pt_regs *regs)
+{
+	ipipe_trace_irq_entry(IPIPE_TIMER_VIRQ);
+
+#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
+
+	__raw_get_cpu_var(__ipipe_tick_regs).nip = regs->nip;
+	__raw_get_cpu_var(__ipipe_tick_regs).msr = regs->msr;
+
+	if (!ipipe_root_domain_p)
+		__raw_get_cpu_var(__ipipe_tick_regs).msr &= ~MSR_EE;
+
+	__ipipe_handle_irq(IPIPE_TIMER_VIRQ, NULL);
+
+#ifndef CONFIG_40x
+	if (__ipipe_decr_ticks != tb_ticks_per_jiffy) {
+		unsigned long long next_date, now;
+
+		next_date = __raw_get_cpu_var(__ipipe_decr_next);
+
+		while ((now = __ipipe_read_timebase()) >= next_date)
+			next_date += __ipipe_decr_ticks;
+
+		set_dec(next_date - now);
+
+		__raw_get_cpu_var(__ipipe_decr_next) = next_date;
+	}
+#endif	/* !CONFIG_40x */
+
+	ipipe_trace_irq_exit(IPIPE_TIMER_VIRQ);
+
+	if (ipipe_root_domain_p) {
+#ifdef CONFIG_PPC_970_NAP
+		struct thread_info *ti = current_thread_info();
+		/* Emulate the napping check when 100% sure we do run
+		 * over the root context. */
+		if (test_and_clear_bit(TLF_NAPPING, &ti->local_flags))
+			regs->nip = regs->link;
+#endif
+		if (!test_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status)))
+			return 1;
+	}
+
+	return 0;
+}
+
+notrace int __ipipe_check_root(void)
+{
+	return ipipe_root_domain_p;
+}
+
+notrace void __ipipe_fast_stall_root(void)
+{
+	set_bit_safe(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+}
+
+notrace void __ipipe_fast_unstall_root(void)
+{
+	clear_bit_safe(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+}
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+notrace void __ipipe_trace_irqsoff(void)
+{
+	ipipe_trace_irqsoff();
+}
+
+notrace void __ipipe_trace_irqson(void)
+{
+	ipipe_trace_irqson();
+}
+
+notrace void __ipipe_trace_irqsx(unsigned long msr_ee)
+{
+	if (msr_ee)
+		ipipe_trace_irqson();
+	else
+		ipipe_trace_irqsoff();
+}
+
+#endif
+
+int __ipipe_syscall_root(struct pt_regs *regs) /* HW interrupts off */
+{
+	struct ipipe_percpu_domain_data *p;
+	unsigned long flags;
+        int ret;
+
+        /*
+         * This routine either returns:
+         * 0 -- if the syscall is to be passed to Linux;
+         * >0 -- if the syscall should not be passed to Linux, and no
+         * tail work should be performed;
+         * <0 -- if the syscall should not be passed to Linux but the
+         * tail work has to be performed (for handling signals etc).
+         */
+
+        if (!__ipipe_syscall_watched_p(current, regs->gpr[0]) ||
+            !__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
+                return 0;
+
+        ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
+
+	local_irq_save_hw(flags);
+
+        if (!ipipe_root_domain_p) {
+		local_irq_restore_hw(flags);
+		return 1;
+	}
+
+	p = ipipe_root_cpudom_ptr();
+	if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+
+	local_irq_restore_hw(flags);
+
+	return -ret;
+}
+
+void __ipipe_pin_range_globally(unsigned long start, unsigned long end)
+{
+	/* We don't support this. */
+}
+
+#ifdef CONFIG_PREEMPT
+
+asmlinkage void __sched preempt_schedule_irq(void);
+
+void __sched  __ipipe_preempt_schedule_irq(void)
+{
+	struct ipipe_percpu_domain_data *p; 
+	unsigned long flags;  
+	/*
+	 * We have no IRQ state fixup on entry to exceptions, so we
+	 * have to stall the root stage before rescheduling.
+	 */  
+#ifdef CONFIG_IPIPE_DEBUG
+	BUG_ON(!irqs_disabled_hw());
+#endif
+	local_irq_save(flags);	
+	local_irq_enable_hw();	
+	preempt_schedule_irq(); /* Ok, may reschedule now. */  
+	local_irq_disable_hw(); 
+	/*
+	 * Flush any pending interrupt that may have been logged after
+	 * preempt_schedule_irq() stalled the root stage before
+	 * returning to us, and now.
+	 */
+	p = ipipe_root_cpudom_ptr(); 
+	if (unlikely(p->irqpend_himask != 0)) { 
+		add_preempt_count(PREEMPT_ACTIVE);
+		clear_bit(IPIPE_STALL_FLAG, &p->status); 
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY); 
+		sub_preempt_count(PREEMPT_ACTIVE);
+	} 
+
+	local_irq_restore_nosync(flags);  
+}
+
+#endif
+
+EXPORT_SYMBOL(__ipipe_decr_ticks);
+EXPORT_PER_CPU_SYMBOL(__ipipe_decr_next);
+EXPORT_SYMBOL(ipipe_critical_enter);
+EXPORT_SYMBOL(ipipe_critical_exit);
+EXPORT_SYMBOL(ipipe_trigger_irq);
+EXPORT_SYMBOL(ipipe_get_sysinfo);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__ipipe_stall_root);
+EXPORT_SYMBOL(__ipipe_test_root);
+EXPORT_SYMBOL(__ipipe_test_and_stall_root);
+#endif
+
+#ifdef CONFIG_PPC_MERGE
+EXPORT_SYMBOL(disarm_decr);
+#endif
+EXPORT_SYMBOL_GPL(__switch_to);
+EXPORT_SYMBOL_GPL(show_stack);
+EXPORT_SYMBOL_GPL(_switch);
+void atomic_set_mask(unsigned long mask, unsigned long *ptr);
+void atomic_clear_mask(unsigned long mask, unsigned long *ptr);
+extern unsigned long context_map[];
+#ifdef FEW_CONTEXTS
+EXPORT_SYMBOL_GPL(nr_free_contexts);
+EXPORT_SYMBOL_GPL(context_mm);
+EXPORT_SYMBOL_GPL(steal_context);
+#endif	/* !FEW_CONTEXTS */
+EXPORT_SYMBOL_GPL(context_map);
+EXPORT_SYMBOL_GPL(atomic_set_mask);
+EXPORT_SYMBOL_GPL(atomic_clear_mask);
+EXPORT_SYMBOL_GPL(last_task_used_math);
+#ifndef CONFIG_LTT
+EXPORT_SYMBOL_GPL(tasklist_lock);
+#endif
+#ifdef CONFIG_IPIPE_TRACE_MCOUNT
+void notrace _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif /* CONFIG_IPIPE_TRACE_MCOUNT */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 0bd8c76..31a4ba3 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -70,7 +70,7 @@
 #endif
 
 int __irq_offset_value;
-static int ppc_spurious_interrupts;
+int ppc_spurious_interrupts;
 
 #ifdef CONFIG_PPC32
 EXPORT_SYMBOL(__irq_offset_value);
@@ -93,8 +93,6 @@ extern atomic_t ipi_sent;
 #endif
 
 #ifdef CONFIG_PPC64
-EXPORT_SYMBOL(irq_desc);
-
 int distribute_irqs = 1;
 
 static inline unsigned long get_hard_enabled(void)
diff --git a/arch/powerpc/kernel/marker.c b/arch/powerpc/kernel/marker.c
new file mode 100644
index 0000000..a75a96f
--- /dev/null
+++ b/arch/powerpc/kernel/marker.c
@@ -0,0 +1,25 @@
+/* marker.c
+ *
+ * Powerpc optimized marker enabling/disabling.
+ *
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ */
+
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/string.h>
+#include <asm/cacheflush.h>
+
+int marker_optimized_set_enable(void *address, char enable)
+{
+	char newi[MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET+1];
+	int size = MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET
+			+ sizeof(MARK_OPTIMIZED_ENABLE_TYPE);
+
+	memcpy(newi, address, size);
+	MARK_OPTIMIZED_ENABLE(&newi[0]) = enable;
+	memcpy(address, newi, size);
+	flush_icache_range((unsigned long)address, size);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(marker_optimized_set_enable);
diff --git a/arch/powerpc/kernel/mcount.S b/arch/powerpc/kernel/mcount.S
new file mode 100644
index 0000000..83faab8
--- /dev/null
+++ b/arch/powerpc/kernel/mcount.S
@@ -0,0 +1,75 @@
+/*
+ *  linux/arch/powerpc/kernel/mcount.S
+ *
+ *  Adapted from glibc's ppc32 profiling support --rpm.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+
+/*
+ * Excerpt from sysdeps/powerpc/powerpc32/ppc-mcount.S
+ *
+ * Do profiling as described in the SYSV ELF ABI, _mcount is called
+ * with the address of a data word in r0 (that is different for every
+ * routine, initialised to 0, and otherwise unused).  The caller has
+ * put the address the caller will return to in the usual place on the stack,
+ * 4(r1).  _mcount is responsible for ensuring that when it returns no
+ * argument-passing registers are disturbed, and that the LR is set back
+ * to (what the caller sees as) 4(r1).
+ *
+ * This is intended so that the following code can be inserted at the
+ * front of any routine without changing the routine:
+ *
+ *	mflr	r0
+ *	lis	r12,0b@ha
+ *	stw	r0,4(r1)
+ *	addi	r0,r12,0b@l
+ *	bl	_mcount
+ */
+
+.globl	_mcount
+_mcount:
+	stwu	r1,-48(r1)
+/* We need to save the parameter-passing registers.  */
+	stw	r3, 12(r1)
+	stw	r4, 16(r1)
+	stw	r5, 20(r1)
+	stw	r6, 24(r1)
+	stw	r7, 28(r1)
+	stw	r8, 32(r1)
+	stw	r9, 36(r1)
+	stw	r10,40(r1)
+	mflr	r4
+	mfcr	r5
+	stw	r4, 44(r1)
+	stw	r5,  8(r1)
+	tophys(r0,0)
+	addis	r6,r0,ipipe_trace_enable@ha
+	lwz	r3,ipipe_trace_enable@l(r6)
+	cmpwi	r3,0
+	beq	1f
+	li	r3,0
+	lwz	r5, 52(r1)
+	li	r6,0
+	bl	__ipipe_trace
+1:	
+ /* Restore the registers...  */
+	lwz     r6,  8(r1)
+	lwz	r0, 44(r1)
+	lwz	r3, 12(r1)
+	mtctr	r0
+	lwz	r4, 16(r1)
+	mtcrf	0xff,r6
+	lwz	r5, 20(r1)
+	lwz	r6, 24(r1)
+	lwz	r0, 52(r1)
+	lwz	r7, 28(r1)
+	lwz	r8, 32(r1)
+	mtlr	r0
+	lwz	r9, 36(r1)
+	lwz	r10,40(r1)
+ /* ...unwind the stack frame, and return to your usual programming.  */
+	addi	r1,r1,48
+	bctr
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 412bea3..3e996c6 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -742,7 +742,7 @@ _GLOBAL(_get_SP)
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(original_kernel_thread)
 	stwu	r1,-16(r1)
 	stw	r30,8(r1)
 	stw	r31,12(r1)
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 21fd2c6..515bf9a 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -387,7 +387,7 @@ _GLOBAL(scom970_write)
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(original_kernel_thread)
 	std	r29,-24(r1)
 	std	r30,-16(r1)
 	stdu	r1,-STACK_FRAME_OVERHEAD(r1)
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 95776b6..0bd4e3b 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -178,7 +178,6 @@ EXPORT_SYMBOL(screen_info);
 
 #ifdef CONFIG_PPC32
 EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(irq_desc);
 EXPORT_SYMBOL(tb_ticks_per_jiffy);
 EXPORT_SYMBOL(console_drivers);
 EXPORT_SYMBOL(cacheable_memcpy);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index f3d4dd5..4fe9466 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -326,7 +326,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
 	}
 #endif
 
-	local_irq_save(flags);
+	local_irq_save_hw(flags);
 
 	account_system_vtime(current);
 	account_process_vtime(current);
@@ -334,7 +334,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
 
 	last = _switch(old_thread, new_thread);
 
-	local_irq_restore(flags);
+	local_irq_restore_hw(flags);
 
 	return last;
 }
@@ -455,6 +455,17 @@ void show_regs(struct pt_regs * regs)
 		show_instructions(regs);
 }
 
+long original_kernel_thread(int (*fn) (void*), void* arg, unsigned long flags);
+
+long kernel_thread(int (fn) (void *), void* arg, unsigned long flags)
+{
+	long retval;
+
+	retval = original_kernel_thread(fn, arg, flags);
+	MARK(kernel_arch_kthread_create, "%ld %p", retval, fn);
+	return retval;
+}
+
 void exit_thread(void)
 {
 	discard_lazy_cpu_state();
@@ -465,8 +476,13 @@ void flush_thread(void)
 #ifdef CONFIG_PPC64
 	struct thread_info *t = current_thread_info();
 
-	if (t->flags & _TIF_ABI_PENDING)
-		t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
+	if (test_ti_thread_flag(t, TIF_ABI_PENDING)) {
+		clear_ti_thread_flag(t, TIF_ABI_PENDING);
+		if (test_ti_thread_flag(t, TIF_32BIT))
+			clear_ti_thread_flag(t, TIF_32BIT);
+		else
+			set_ti_thread_flag(t, TIF_32BIT);
+	}
 #endif
 
 	discard_lazy_cpu_state();
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 1fc732a..84ef63e 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1019,8 +1019,6 @@ void __init early_init_devtree(void *params)
 	DBG(" <- early_init_devtree()\n");
 }
 
-#undef printk
-
 int
 prom_n_addr_cells(struct device_node* np)
 {
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 975102a..46af44d 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -526,6 +526,8 @@ static void do_syscall_trace(void)
 
 void do_syscall_trace_enter(struct pt_regs *regs)
 {
+	MARK(kernel_arch_syscall_entry, "%d %ld",
+		(int)regs->gpr[0], instruction_pointer(regs));
 	secure_computing(regs->gpr[0]);
 
 	if (test_thread_flag(TIF_SYSCALL_TRACE)
@@ -546,6 +548,8 @@ void do_syscall_trace_enter(struct pt_regs *regs)
 
 void do_syscall_trace_leave(struct pt_regs *regs)
 {
+	MARK(kernel_arch_syscall_exit, MARK_NOARGS);
+
 	if (unlikely(current->audit_context))
 		audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
 				   regs->result);
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 61c65d1..2fff51b 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -65,6 +65,7 @@ int have_of = 1;
 
 #ifdef CONFIG_VGA_CONSOLE
 unsigned long vgacon_remap_base;
+EXPORT_SYMBOL(vgacon_remap_base);
 #endif
 
 /*
@@ -84,7 +85,7 @@ int ucache_bsize;
  * from the address that it was linked at, so we must use RELOC/PTRRELOC
  * to access static data (including strings).  -- paulus
  */
-unsigned long __init early_init(unsigned long dt_ptr)
+unsigned long notrace __init early_init(unsigned long dt_ptr)
 {
 	unsigned long offset = reloc_offset();
 	struct cpu_spec *spec;
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index d358866..1bb0a1d 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -57,6 +57,8 @@ int sys_ipc(uint call, int first, unsigned long second, long third,
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
+	MARK(kernel_arch_ipc_call, "%u %d", call, first);
+
 	ret = -ENOSYS;
 	switch (call) {
 	case SEMOP:
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f6f0c6b..fc49da5 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -74,6 +74,8 @@
 #endif
 #include <asm/smp.h>
 
+unsigned long disarm_decr[NR_CPUS];
+
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 #ifdef CONFIG_PPC_ISERIES
@@ -296,7 +298,25 @@ static void snapshot_purr(void)
 
 #else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
 #define calc_cputime_factors()
+#ifdef CONFIG_IPIPE
+static void account_process_time(struct pt_regs *regs)
+{
+	int cpu, user_tick = user_mode(regs);
+
+	if (regs->msr & MSR_EE) {
+		update_process_times(user_tick);
+		return;
+	}
+
+	run_local_timers();
+	cpu = smp_processor_id();
+	if (rcu_pending(cpu))
+		rcu_check_callbacks(cpu, user_tick);
+	run_posix_cpu_timers(current);
+}
+#else
 #define account_process_time(regs)	update_process_times(user_mode(regs))
+#endif
 #define calculate_steal_time()		do { } while (0)
 #endif
 
@@ -618,6 +638,9 @@ void timer_interrupt(struct pt_regs * regs)
 	int cpu = smp_processor_id();
 	unsigned long ticks;
 	u64 tb_next_jiffy;
+	
+	MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+		instruction_pointer(regs));
 
 #ifdef CONFIG_PPC32
 	if (atomic_read(&ppc_n_lost_interrupts) != 0)
@@ -625,7 +648,9 @@ void timer_interrupt(struct pt_regs * regs)
 #endif
 
 	old_regs = set_irq_regs(regs);
+#ifndef CONFIG_IPIPE
 	irq_enter();
+#endif
 
 	profile_tick(CPU_PROFILING);
 	calculate_steal_time();
@@ -672,7 +697,8 @@ void timer_interrupt(struct pt_regs * regs)
 	}
 	
 	next_dec = tb_ticks_per_jiffy - ticks;
-	set_dec(next_dec);
+	if ( !disarm_decr[cpu] )
+	    set_dec(next_dec);
 
 #ifdef CONFIG_PPC_ISERIES
 	if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending())
@@ -687,8 +713,12 @@ void timer_interrupt(struct pt_regs * regs)
 	}
 #endif
 
+#ifndef CONFIG_IPIPE
 	irq_exit();
+#endif
 	set_irq_regs(old_regs);
+
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 void wakeup_decrementer(void)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 535f506..a042e90 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -33,6 +33,7 @@
 #include <linux/kexec.h>
 #include <linux/backlight.h>
 #include <linux/bug.h>
+#include <linux/ltt-core.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -132,6 +133,11 @@ int die(const char *str, struct pt_regs *regs, long err)
 	printk("%s\n", ppc_md.name ? "" : ppc_md.name);
 
 	print_modules();
+#ifdef CONFIG_LTT
+	printk("LTT NESTING LEVEL : %u ",
+			ltt_nesting[smp_processor_id()]);
+	printk("\n");
+#endif
 	show_regs(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -161,6 +167,9 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 			return;
 	}
 
+	MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+		instruction_pointer(regs));
+
 	memset(&info, 0, sizeof(info));
 	info.si_signo = signr;
 	info.si_code = code;
@@ -188,6 +197,8 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 			do_exit(signr);
 		}
 	}
+
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 #ifdef CONFIG_PPC64
@@ -321,6 +332,9 @@ void machine_check_exception(struct pt_regs *regs)
 	int recover = 0;
 	unsigned long reason = get_mc_reason(regs);
 
+	if (ipipe_trap_notify(IPIPE_TRAP_MCE,regs))
+	    	return;
+
 	/* See if any machine dependent calls */
 	if (ppc_md.machine_check_exception)
 		recover = ppc_md.machine_check_exception(regs);
@@ -490,11 +504,17 @@ void unknown_exception(struct pt_regs *regs)
 	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
 	       regs->nip, regs->msr, regs->trap);
 
+	if (ipipe_trap_notify(IPIPE_TRAP_UNKNOWN,regs))
+	    	return;
+
 	_exception(SIGTRAP, regs, 0, 0);
 }
 
 void instruction_breakpoint_exception(struct pt_regs *regs)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_IABR,regs))
+	    	return;
+
 	if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5,
 					5, SIGTRAP) == NOTIFY_STOP)
 		return;
@@ -505,6 +525,8 @@ void instruction_breakpoint_exception(struct pt_regs *regs)
 
 void RunModeException(struct pt_regs *regs)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_RM,regs))
+	    	return;
 	_exception(SIGTRAP, regs, 0, 0);
 }
 
@@ -512,6 +534,9 @@ void __kprobes single_step_exception(struct pt_regs *regs)
 {
 	regs->msr &= ~(MSR_SE | MSR_BE);  /* Turn off 'trace' bits */
 
+	if (ipipe_trap_notify(IPIPE_TRAP_SSTEP,regs))
+	    return;
+
 	if (notify_die(DIE_SSTEP, "single_step", regs, 5,
 					5, SIGTRAP) == NOTIFY_STOP)
 		return;
@@ -531,6 +556,8 @@ static void emulate_single_step(struct pt_regs *regs)
 {
 	if (single_stepping(regs)) {
 		clear_single_step(regs);
+		if (ipipe_trap_notify(IPIPE_TRAP_SSTEP,regs))
+		    return;
 		_exception(SIGTRAP, regs, TRAP_TRACE, 0);
 	}
 }
@@ -754,6 +781,9 @@ void __kprobes program_check_exception(struct pt_regs *regs)
 	}
 #endif /* CONFIG_MATH_EMULATION */
 
+	if (ipipe_trap_notify(IPIPE_TRAP_PCE,regs))
+	    	return;
+
 	if (reason & REASON_FP) {
 		/* IEEE FP exception */
 		parse_fpe(regs);
@@ -801,6 +831,9 @@ void alignment_exception(struct pt_regs *regs)
 {
 	int sig, code, fixed = 0;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ALIGNMENT,regs))
+	    	return;
+
 	/* we don't implement logging of alignment exceptions */
 	if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS))
 		fixed = fix_alignment(regs);
@@ -838,6 +871,8 @@ void nonrecoverable_exception(struct pt_regs *regs)
 {
 	printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n",
 	       regs->nip, regs->msr);
+	if (ipipe_trap_notify(IPIPE_TRAP_NREC,regs))
+	    	return;
 	debugger(regs);
 	die("nonrecoverable exception", regs, SIGKILL);
 }
@@ -853,11 +888,16 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs)
 {
 	printk(KERN_EMERG "Unrecoverable FP Unavailable Exception "
 			  "%lx at %lx\n", regs->trap, regs->nip);
+	if (ipipe_trap_notify(IPIPE_TRAP_KFPUNAVAIL,regs))
+	    	return;
 	die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);
 }
 
 void altivec_unavailable_exception(struct pt_regs *regs)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_ALTUNAVAIL,regs))
+	    	return;
+
 	if (user_mode(regs)) {
 		/* A user program has executed an altivec instruction,
 		   but this kernel doesn't support altivec. */
@@ -872,7 +912,10 @@ void altivec_unavailable_exception(struct pt_regs *regs)
 
 void performance_monitor_exception(struct pt_regs *regs)
 {
+	MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+		instruction_pointer(regs));
 	perf_irq(regs);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 #ifdef CONFIG_8xx
@@ -882,6 +925,9 @@ void SoftwareEmulation(struct pt_regs *regs)
 	extern int Soft_emulate_8xx(struct pt_regs *);
 	int errcode;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_SOFTEMU,regs))
+	    	return;
+
 	CHECK_FULL_REGS(regs);
 
 	if (!user_mode(regs)) {
@@ -910,6 +956,9 @@ void SoftwareEmulation(struct pt_regs *regs)
 
 void DebugException(struct pt_regs *regs, unsigned long debug_status)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_DEBUG,regs))
+	    	return;
+
 	if (debug_status & DBSR_IC) {	/* instruction completion */
 		regs->msr &= ~MSR_DE;
 		if (user_mode(regs)) {
@@ -940,6 +989,9 @@ void altivec_assist_exception(struct pt_regs *regs)
 {
 	int err;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ALTASSIST,regs))
+	    	return;
+
 	if (!user_mode(regs)) {
 		printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode"
 		       " at %lx\n", regs->nip);
@@ -959,12 +1011,15 @@ void altivec_assist_exception(struct pt_regs *regs)
 		/* got an error reading the instruction */
 		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
 	} else {
+		MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+			instruction_pointer(regs));
 		/* didn't recognize the instruction */
 		/* XXX quick hack for now: set the non-Java bit in the VSCR */
 		if (printk_ratelimit())
 			printk(KERN_ERR "Unrecognized altivec instruction "
 			       "in %s at %lx\n", current->comm, regs->nip);
 		current->thread.vscr.u[3] |= 0x10000;
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 	}
 }
 #endif /* CONFIG_ALTIVEC */
@@ -977,8 +1032,11 @@ void CacheLockingException(struct pt_regs *regs, unsigned long address,
 	 * as priv ops, in the future we could try to do
 	 * something smarter
 	 */
-	if (error_code & (ESR_DLK|ESR_ILK))
+	if (error_code & (ESR_DLK|ESR_ILK)) {
+		if (ipipe_trap_notify(IPIPE_TRAP_CACHE,regs))
+			return;
 		_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+	}
 	return;
 }
 #endif /* CONFIG_FSL_BOOKE */
@@ -990,6 +1048,9 @@ void SPEFloatingPointException(struct pt_regs *regs)
 	int fpexc_mode;
 	int code = 0;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_SPE,regs))
+	    	return;
+
 	spefscr = current->thread.spefscr;
 	fpexc_mode = current->thread.fpexc_mode;
 
@@ -1029,6 +1090,8 @@ void unrecoverable_exception(struct pt_regs *regs)
 {
 	printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n",
 	       regs->trap, regs->nip);
+	if (ipipe_trap_notify(IPIPE_TRAP_NREC,regs))
+	    	return;
 	die("Unrecoverable exception", regs, SIGABRT);
 }
 
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 04b8e71..40ecdb8 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -174,11 +174,13 @@ SECTIONS
 		*(.data)
 		*(.sdata)
 		*(.got.plt) *(.got)
+		EXTRA_RWDATA
 	}
 #else
 	.data : {
 		*(.data .data.rel* .toc1)
 		*(.branch_lt)
+		EXTRA_RWDATA
 	}
 
 	.opd : {
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 03aeb3a..7f1a4fb 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -153,13 +153,17 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
 			    unsigned long error_code)
 {
 	struct vm_area_struct * vma;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm;
 	siginfo_t info;
 	int code = SEGV_MAPERR;
 	int is_write = 0;
 	int trap = TRAP(regs);
  	int is_exec = trap == 0x400;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
+	    	return 0;
+
+	mm = current->mm;
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
 	/*
 	 * Fortunately the bit assignments in SRR1 for an instruction
@@ -343,17 +347,23 @@ good_area:
 	 * the fault.
 	 */
  survive:
+ 	MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+		instruction_pointer(regs));
 	switch (handle_mm_fault(mm, vma, address, is_write)) {
 
 	case VM_FAULT_MINOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		current->min_flt++;
 		break;
 	case VM_FAULT_MAJOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		current->maj_flt++;
 		break;
 	case VM_FAULT_SIGBUS:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		goto do_sigbus;
 	case VM_FAULT_OOM:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		goto out_of_memory;
 	default:
 		BUG();
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 5225abf..ccd3c3c 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -81,7 +81,7 @@ struct pci_event {
 	} data;
 };
 
-static DEFINE_SPINLOCK(pending_irqs_lock);
+static IPIPE_DEFINE_SPINLOCK(pending_irqs_lock);
 static int num_pending_irqs;
 static int pending_irqs[NR_IRQS];
 
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 39db128..c3db17f 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -63,7 +63,7 @@ static int max_irqs;
 static int max_real_irqs;
 static u32 level_mask[4];
 
-static DEFINE_SPINLOCK(pmac_pic_lock);
+static IPIPE_DEFINE_SPINLOCK(pmac_pic_lock);
 
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
 static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 6f5de43..4aa0db1 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -318,7 +318,7 @@ struct bmp {
 		unsigned long mask;
 		unsigned long unused_2[3];
 	} __attribute__ ((packed));
-	spinlock_t lock;
+	ipipe_spinlock_t lock;
 	unsigned long ipi_debug_brk_mask;
 };
 
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index ad87adc..107a70c 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -23,7 +23,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff };
 #define cached_A1 (cached_8259[0])
 #define cached_21 (cached_8259[1])
 
-static DEFINE_SPINLOCK(i8259_lock);
+static IPIPE_DEFINE_SPINLOCK(i8259_lock);
 
 static struct device_node *i8259_node;
 static struct irq_host *i8259_host;
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 746f78c..0e57eb3 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -30,7 +30,7 @@
 #include "ipic.h"
 
 static struct ipic * primary_ipic;
-static DEFINE_SPINLOCK(ipic_lock);
+static IPIPE_DEFINE_SPINLOCK(ipic_lock);
 
 static struct ipic_info ipic_info[] = {
 	[9] = {
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index d01ced1..8500b35 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -44,7 +44,7 @@
 
 static struct mpic *mpics;
 static struct mpic *mpic_primary;
-static DEFINE_SPINLOCK(mpic_lock);
+static IPIPE_DEFINE_SPINLOCK(mpic_lock);
 
 #ifdef CONFIG_PPC32	/* XXX for now */
 #ifdef CONFIG_IRQ_ALL_CPUS
@@ -555,28 +555,33 @@ static void mpic_unmask_irq(unsigned int irq)
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
+	unsigned long flags;
 
 	DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
 
+	local_irq_save_hw_cond(flags);
+
 	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
 		       mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
 		       ~MPIC_VECPRI_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
 		if (!loops--) {
-			printk(KERN_ERR "mpic_enable_irq timeout\n");
+			printk(KERN_ERR "mpic_unmask_irq timeout (irq %u)\n", irq);
 			break;
 		}
 	} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
+
+	ipipe_irq_unlock(irq);
+
+	local_irq_restore_hw_cond(flags);
 }
 
-static void mpic_mask_irq(unsigned int irq)
+static inline void __mpic_mask_irq(unsigned int irq)
 {
-	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
 	unsigned int src = mpic_irq_to_hw(irq);
-
-	DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
+	unsigned int loops = 100000;
 
 	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
 		       mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
@@ -585,12 +590,27 @@ static void mpic_mask_irq(unsigned int irq)
 	/* make sure mask gets to controller before we return to user */
 	do {
 		if (!loops--) {
-			printk(KERN_ERR "mpic_enable_irq timeout\n");
+			printk(KERN_ERR "mpic_mask_irq timeout, irq %u\n", irq);
 			break;
 		}
 	} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
 }
 
+void mpic_mask_irq(unsigned int irq)
+{
+#ifdef DEBUG
+	struct mpic *mpic = mpic_from_irq(irq);
+#endif
+	unsigned long flags;
+
+	DBG("%s: mask_irq: irq %u (src %d)\n", mpic->name, irq, mpic_irq_to_hw(irq));
+
+	local_irq_save_hw_cond(flags);
+	__mpic_mask_irq(irq);
+	ipipe_irq_lock(irq);
+	local_irq_restore_hw_cond(flags);
+}
+
 static void mpic_end_irq(unsigned int irq)
 {
 	struct mpic *mpic = mpic_from_irq(irq);
@@ -603,6 +623,9 @@ static void mpic_end_irq(unsigned int irq)
 	 * latched another edge interrupt coming in anyway
 	 */
 
+#ifdef CONFIG_IPIPE
+	__mpic_mask_irq(irq);
+#endif
 	mpic_eoi(mpic);
 }
 
@@ -647,6 +670,9 @@ static void mpic_end_ht_irq(unsigned int irq)
 #ifdef DEBUG_IRQ
 	DBG("%s: end_irq: %d\n", mpic->name, irq);
 #endif
+#ifdef CONFIG_IPIPE
+	__mpic_mask_irq(irq);
+#endif
 	/* We always EOI on end_irq() even for edge interrupts since that
 	 * should only lower the priority, the MPIC should have properly
 	 * latched another edge interrupt coming in anyway
@@ -730,6 +756,7 @@ static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 	unsigned int src = mpic_irq_to_hw(virq);
 	struct irq_desc *desc = get_irq_desc(virq);
 	unsigned int vecpri, vold, vnew;
+	unsigned long flags;
 
 	DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
 	    mpic, virq, src, flow_type);
@@ -754,6 +781,8 @@ static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 	else
 		vecpri = mpic_type_to_vecpri(mpic, flow_type);
 
+	local_irq_save_hw_cond(flags);
+
 	vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
 	vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) |
 			MPIC_INFO(VECPRI_SENSE_MASK));
@@ -761,6 +790,8 @@ static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 	if (vold != vnew)
 		mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew);
 
+	local_irq_restore_hw_cond(flags);
+
 	return 0;
 }
 
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index ae249c6..cde8ae9 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -249,7 +249,9 @@ static void tsi108_pci_int_mask(u_int irq)
 {
 	u_int irp_cfg;
 	int int_line = (irq - IRQ_PCI_INTAD_BASE);
+	unsigned long flags;
 
+	local_irq_save_hw_cond(flags);
 	irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
 	mb();
 	irp_cfg |= (1 << int_line);	/* INTx_DIR = output */
@@ -257,19 +259,23 @@ static void tsi108_pci_int_mask(u_int irq)
 	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg);
 	mb();
 	irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
+	local_irq_restore_hw_cond(flags);
 }
 
 static void tsi108_pci_int_unmask(u_int irq)
 {
 	u_int irp_cfg;
 	int int_line = (irq - IRQ_PCI_INTAD_BASE);
+	unsigned long flags;
 
+	local_irq_save_hw_cond(flags);
 	irp_cfg = tsi108_read_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL);
 	mb();
 	irp_cfg &= ~(1 << int_line);
 	irp_cfg |= (3 << (8 + (int_line * 2)));
 	tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL, irp_cfg);
 	mb();
+	local_irq_restore_hw_cond(flags);
 }
 
 static void init_pci_source(void)
@@ -360,6 +366,9 @@ static void tsi108_pci_irq_ack(u_int irq)
 
 static void tsi108_pci_irq_end(u_int irq)
 {
+	unsigned long flags;
+
+	local_irq_save_hw_cond(flags);
 	tsi108_pci_int_unmask(irq);
 
 	/* Enable interrupts from PCI block */
@@ -367,6 +376,7 @@ static void tsi108_pci_irq_end(u_int irq)
 			 tsi108_read_reg(TSI108_PCI_OFFSET +
 					 TSI108_PCI_IRP_ENABLE) |
 			 TSI108_PCI_IRP_ENABLE_P_INT);
+	local_irq_restore_hw_cond(flags);
 	mb();
 }
 
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 8eb82ef..1a9b262 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -290,6 +290,8 @@ endmenu
 
 menu "Platform options"
 
+source "kernel/ipipe/Kconfig"
+
 config FADS
 	bool
 
@@ -1441,8 +1443,16 @@ endmenu
 
 source "lib/Kconfig"
 
+menu "Instrumentation Support"
+
 source "arch/powerpc/oprofile/Kconfig"
 
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/ppc/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index b739e25..1af5a88 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -16,6 +16,14 @@
 CFLAGS	 	+= -fno-builtin -D__BOOTER__ -Iarch/$(ARCH)/boot/include
 HOSTCFLAGS	+= -Iarch/$(ARCH)/boot/include
 
+ifdef CONFIG_IPIPE_TRACE
+# do not trace the boot loader
+nullstring :=
+space      := $(nullstring) # end of the line
+pg_flag     = $(nullstring) -pg # end of the line
+CFLAGS     := $(subst ${pg_flag},${space},${CFLAGS})
+endif
+
 BOOT_TARGETS	= zImage zImage.initrd znetboot znetboot.initrd
 
 bootdir-y			:= simple
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index a9d4553..50cf81a 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -132,8 +132,23 @@ transfer_to_handler:
          * check for stack overflow
          */
 	lwz	r9,THREAD_INFO-THREAD(r12)
+#ifdef CONFIG_IPIPE
+	/* Allow for private kernel-based stacks: those must not cause
+	the stack overflow detection to trigger when some activity has
+	been preempted over them. We just check if the kernel stack is
+	not treading on the memory area ranging from
+	&current->thread_info to &current->thread, which is coarser
+	than the vanilla implementation, but likely sensitive enough
+	to catch overflows soon enough though.*/
+	addi	r12,r9,THREAD
+	cmplw	0,r1,r9
+	cmplw	1,r1,r12
+	crand	1,1,4
+	bgt-	stack_ovf		/* if r9 < r1 < r9+THREAD */
+#else /* CONFIG_IPIPE */
 	cmplw	r1,r9			/* if r1 <= current->thread_info */
 	ble-	stack_ovf		/* then the kernel stack overflowed */
+#endif /* CONFIG_IPIPE */
 5:
 #ifdef CONFIG_6xx
 	tophys(r9,r9)			/* check local flags */
@@ -198,6 +213,21 @@ _GLOBAL(DoSyscall)
 	lwz	r11,_CCR(r1)	/* Clear SO bit in CR */
 	rlwinm	r11,r11,0,4,2
 	stw	r11,_CCR(r1)
+#ifdef CONFIG_IPIPE
+	addi	r3,r1,GPR0
+	bl	__ipipe_syscall_root
+	cmpwi	r3,0
+	lwz	r3,GPR3(r1)
+	lwz	r0,GPR0(r1)
+	lwz	r4,GPR4(r1)
+	lwz	r5,GPR5(r1)
+	lwz	r6,GPR6(r1)
+	lwz	r7,GPR7(r1)
+	lwz	r8,GPR8(r1)
+	lwz	r9,GPR9(r1)
+	bgt	.ipipe_end_syscall
+	blt	ret_from_syscall
+#endif /* CONFIG_IPIPE */
 #ifdef SHOW_SYSCALLS
 	bl	do_show_syscall
 #endif /* SHOW_SYSCALLS */
@@ -260,11 +290,34 @@ syscall_exit_cont:
 	SYNC
 	RFI
 
+#ifdef CONFIG_IPIPE
+.ipipe_end_syscall:
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)	/* doesn't include MSR_EE */
+	SYNC
+	MTMSRD(r10)
+	b syscall_exit_cont
+#endif /* CONFIG_IPIPE */
+
 66:	li	r3,-ENOSYS
 	b	ret_from_syscall
 
 	.globl	ret_from_fork
 ret_from_fork:
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	stwu	r1,-4(r1)
+	stw	r3,0(r1)
+	lis	r3,(0x80000000)@h
+	ori	r3,r3,(0x80000000)@l
+	bl	ipipe_trace_end
+	lwz	r3,0(r1)
+	addi	r1,r1,4
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
+	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)
+#endif /* CONFIG_IPIPE */
 	REST_NVGPRS(r1)
 	bl	schedule_tail
 	li	r3,0
@@ -630,6 +683,11 @@ 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
@@ -665,11 +723,37 @@ resume_kernel:
 	beq+	restore
 	andi.	r0,r3,MSR_EE	/* interrupts off? */
 	beq	restore		/* don't schedule if so */
+#ifdef CONFIG_IPIPE
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	lis	r3,(0x80000000)@h
+	ori	r3,r3,(0x80000000)@l
+	bl	ipipe_trace_end
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
+	ori	r10,r10,MSR_EE
+	SYNC
+	MTMSRD(r10)
+	bl	__ipipe_fast_stall_root
+#endif /* CONFIG_IPIPE */
 1:	bl	preempt_schedule_irq
 	rlwinm	r9,r1,0,0,18
 	lwz	r3,TI_FLAGS(r9)
 	andi.	r0,r3,_TIF_NEED_RESCHED
 	bne-	1b
+#ifdef CONFIG_IPIPE
+	bl	__ipipe_fast_unstall_root
+	LOAD_MSR_KERNEL(r10,MSR_KERNEL)
+	SYNC
+	MTMSRD(r10)
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+	lwz	r3,_MSR(r1)
+	andi.	r0,r3,MSR_EE
+	bne	restore
+	lis	r3,(0x80000000)@h
+	ori	r3,r3,(0x80000000)@l
+	bl	ipipe_trace_begin
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+#endif /* CONFIG_IPIPE */
 #else
 resume_kernel:
 #endif /* CONFIG_PREEMPT */
@@ -891,6 +975,13 @@ do_user_signal:			/* r10 contains MSR_KERNEL here */
 	REST_NVGPRS(r1)
 	b	recheck
 
+#ifdef CONFIG_IPIPE
+_GLOBAL(__ipipe_ret_from_except)
+        cmpwi   r3, 0
+        bne+ ret_from_except
+        b restore
+#endif /* CONFIG_IPIPE */
+
 /*
  * We come here when we are at the end of handling an exception
  * that occurred at a place where taking an exception will lose
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 100052a..107f3a3 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -295,6 +295,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)
@@ -356,7 +362,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
@@ -381,7 +391,11 @@ FPUnavailable:
 	EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
 
 /* 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, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
index 7e44de5..4970a8b 100644
--- a/arch/ppc/kernel/head_44x.S
+++ b/arch/ppc/kernel/head_44x.S
@@ -426,8 +426,11 @@ interrupt_base:
 	/* Instruction Storage Interrupt */
 	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 --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
index 51da157..7a24f9f 100644
--- a/arch/ppc/kernel/head_4xx.S
+++ b/arch/ppc/kernel/head_4xx.S
@@ -228,6 +228,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 --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
index 944c35c..0e2955d 100644
--- a/arch/ppc/kernel/head_8xx.S
+++ b/arch/ppc/kernel/head_8xx.S
@@ -187,6 +187,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)
@@ -238,7 +244,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
@@ -259,7 +269,11 @@ Alignment:
 	EXCEPTION(0x800, FPUnavailable, unknown_exception, 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, unknown_exception, EXC_XFER_EE)
 	EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
index f3d274c..ff295c2 100644
--- a/arch/ppc/kernel/head_booke.h
+++ b/arch/ppc/kernel/head_booke.h
@@ -187,6 +187,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)
@@ -345,6 +351,15 @@ label:
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				      \
 	EXC_XFER_STD(0x0700, program_check_exception)
 
+#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;					      \
@@ -352,6 +367,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 --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index 66877bd..1846753 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -526,7 +526,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 --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index d319f9b..c551433 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -841,7 +841,7 @@ _GLOBAL(_get_SP)
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(original_kernel_thread)
 	stwu	r1,-16(r1)
 	stw	r30,8(r1)
 	stw	r31,12(r1)
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index c8b65ca..8d16b18 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -223,7 +223,6 @@ EXPORT_SYMBOL(screen_info);
 
 EXPORT_SYMBOL(__delay);
 EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(irq_desc);
 EXPORT_SYMBOL(tb_ticks_per_jiffy);
 EXPORT_SYMBOL(console_drivers);
 #ifdef CONFIG_XMON
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 3c506af..78193b2 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -87,6 +87,7 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
 
 #ifdef CONFIG_VGA_CONSOLE
 unsigned long vgacon_remap_base;
+EXPORT_SYMBOL(vgacon_remap_base);
 #endif
 
 struct machdep_calls ppc_md;
@@ -294,7 +295,7 @@ struct seq_operations cpuinfo_op = {
  * from the address that it was linked at, so we must use RELOC/PTRRELOC
  * to access static data (including strings).  -- paulus
  */
-__init
+__init notrace
 unsigned long
 early_init(int r3, int r4, int r5)
 {
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 18ee851..377eb38 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -54,6 +54,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/time.h>
+#include <linux/posix-timers.h>
 #include <linux/init.h>
 #include <linux/profile.h>
 
@@ -63,6 +64,7 @@
 #include <asm/8xx_immap.h>
 #include <asm/machdep.h>
 #include <asm/irq_regs.h>
+#include <asm/ltt.h>
 
 #include <asm/time.h>
 
@@ -70,6 +72,8 @@ unsigned long disarm_decr[NR_CPUS];
 
 extern struct timezone sys_tz;
 
+unsigned long disarm_decr[NR_CPUS];
+
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 
@@ -101,6 +105,33 @@ static inline int tb_delta(unsigned *jiffy_stamp) {
 	return delta;
 }
 
+#ifdef CONFIG_IPIPE
+
+static inline void update_root_process_times(struct pt_regs *regs)
+{
+	int cpu, user_tick = user_mode(regs);
+
+	if (regs->msr & MSR_EE) {
+		update_process_times(user_tick);
+		return;
+	}
+
+	run_local_timers();
+	cpu = smp_processor_id();
+	if (rcu_pending(cpu))
+		rcu_check_callbacks(cpu, user_tick);
+	run_posix_cpu_timers(current);
+}
+
+#else /* !CONFIG_IPIPE */
+
+static inline void update_root_process_times(struct pt_regs *regs)
+{
+	update_process_times(user_mode(regs));
+}
+
+#endif	/* !CONFIG_IPIPE */
+
 #ifdef CONFIG_SMP
 unsigned long profile_pc(struct pt_regs *regs)
 {
@@ -136,17 +167,22 @@ void timer_interrupt(struct pt_regs * regs)
 	unsigned jiffy_stamp = last_jiffy_stamp(cpu);
 	extern void do_IRQ(struct pt_regs *);
 
+	MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+		instruction_pointer(regs));
+
 	if (atomic_read(&ppc_n_lost_interrupts) != 0)
 		do_IRQ(regs);
 
 	old_regs = set_irq_regs(regs);
+#ifndef CONFIG_IPIPE
 	irq_enter();
+#endif
 
 	while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) {
 		jiffy_stamp += tb_ticks_per_jiffy;
 		
 		profile_tick(CPU_PROFILING);
-		update_process_times(user_mode(regs));
+		update_root_process_times(regs);
 
 	  	if (smp_processor_id())
 			continue;
@@ -154,6 +190,9 @@ void timer_interrupt(struct pt_regs * regs)
 		/* We are in an interrupt, no need to save/restore flags */
 		write_seqlock(&xtime_lock);
 		tb_last_stamp = jiffy_stamp;
+#ifdef CONFIG_LTT
+		ltt_reset_timestamp();
+#endif //CONFIG_LTT
 		do_timer(1);
 
 		/*
@@ -183,15 +222,18 @@ void timer_interrupt(struct pt_regs * regs)
 		}
 		write_sequnlock(&xtime_lock);
 	}
-	if ( !disarm_decr[smp_processor_id()] )
+	if ( !disarm_decr[cpu] )
 		set_dec(next_dec);
 	last_jiffy_stamp(cpu) = jiffy_stamp;
 
 	if (ppc_md.heartbeat && !ppc_md.heartbeat_count--)
 		ppc_md.heartbeat();
 
+#ifndef CONFIG_IPIPE
 	irq_exit();
+#endif
 	set_irq_regs(old_regs);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 /*
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 810f7aa..e0b2543 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -107,11 +107,14 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 		debugger(regs);
 		die("Exception in kernel mode", regs, signr);
 	}
+	MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+		instruction_pointer(regs));
 	info.si_signo = signr;
 	info.si_errno = 0;
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
 	force_sig_info(signr, &info, current);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 
 	/*
 	 * Init gets no signals that it doesn't have a handler for.
@@ -234,6 +237,9 @@ void machine_check_exception(struct pt_regs *regs)
 {
 	unsigned long reason = get_mc_reason(regs);
 
+ 	if (ipipe_trap_notify(IPIPE_TRAP_MCE,regs))
+ 	    	return;
+ 
 	if (user_mode(regs)) {
 		regs->msr |= MSR_RI;
 		_exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
@@ -395,11 +401,18 @@ void unknown_exception(struct pt_regs *regs)
 {
 	printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx    %s\n",
 	       regs->nip, regs->msr, regs->trap, print_tainted());
+
+ 	if (ipipe_trap_notify(IPIPE_TRAP_UNKNOWN,regs))
+ 	    	return;
+ 
 	_exception(SIGTRAP, regs, 0, 0);
 }
 
 void instruction_breakpoint_exception(struct pt_regs *regs)
 {
+ 	if (ipipe_trap_notify(IPIPE_TRAP_IABR,regs))
+ 	    	return;
+ 
 	if (debugger_iabr_match(regs))
 		return;
 	_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
@@ -407,6 +420,8 @@ void instruction_breakpoint_exception(struct pt_regs *regs)
 
 void RunModeException(struct pt_regs *regs)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_RM,regs))
+	    	return;
 	_exception(SIGTRAP, regs, 0, 0);
 }
 
@@ -556,6 +571,8 @@ static void emulate_single_step(struct pt_regs *regs)
 {
 	if (single_stepping(regs)) {
 		clear_single_step(regs);
+		if (ipipe_trap_notify(IPIPE_TRAP_SSTEP,regs))
+		    return;
 		_exception(SIGTRAP, regs, TRAP_TRACE, 0);
 	}
 }
@@ -584,6 +601,9 @@ void program_check_exception(struct pt_regs *regs)
 	}
 #endif /* CONFIG_MATH_EMULATION */
 
+	if (ipipe_trap_notify(IPIPE_TRAP_PCE,regs))
+	    	return;
+
 	if (reason & REASON_FP) {
 		/* IEEE FP exception */
 		int code = 0;
@@ -649,6 +669,10 @@ void program_check_exception(struct pt_regs *regs)
 void single_step_exception(struct pt_regs *regs)
 {
 	regs->msr &= ~(MSR_SE | MSR_BE);  /* Turn off 'trace' bits */
+
+ 	if (ipipe_trap_notify(IPIPE_TRAP_SSTEP,regs))
+ 	    return;
+ 
 	if (debugger_sstep(regs))
 		return;
 	_exception(SIGTRAP, regs, TRAP_TRACE, 0);
@@ -658,6 +682,9 @@ void alignment_exception(struct pt_regs *regs)
 {
 	int sig, code, fixed = 0;
 
+ 	if (ipipe_trap_notify(IPIPE_TRAP_ALIGNMENT,regs))
+ 	    	return;
+ 
 	fixed = fix_alignment(regs);
 	if (fixed == 1) {
 		regs->nip += 4;	/* skip over emulated instruction */
@@ -690,6 +717,8 @@ void nonrecoverable_exception(struct pt_regs *regs)
 {
 	printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n",
 	       regs->nip, regs->msr);
+	if (ipipe_trap_notify(IPIPE_TRAP_NREC,regs))
+	    	return;
 	debugger(regs);
 	die("nonrecoverable exception", regs, SIGKILL);
 }
@@ -708,6 +737,9 @@ void SoftwareEmulation(struct pt_regs *regs)
 	extern int Soft_emulate_8xx(struct pt_regs *);
 	int errcode;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_SOFTEMU,regs))
+	    	return;
+
 	CHECK_FULL_REGS(regs);
 
 	if (!user_mode(regs)) {
@@ -736,6 +768,9 @@ void SoftwareEmulation(struct pt_regs *regs)
 
 void DebugException(struct pt_regs *regs, unsigned long debug_status)
 {
+	if (ipipe_trap_notify(IPIPE_TRAP_DEBUG,regs))
+	    	return;
+
 	if (debug_status & DBSR_IC) {	/* instruction completion */
 		regs->msr &= ~MSR_DE;
 		if (user_mode(regs)) {
@@ -768,6 +803,8 @@ void TAUException(struct pt_regs *regs)
 void kernel_fp_unavailable_exception(struct pt_regs *regs)
 {
 	regs->msr |= MSR_FP;
+ 	if (ipipe_trap_notify(IPIPE_TRAP_KFPUNAVAIL,regs))
+ 	    	return;
 	printk(KERN_ERR "floating point used in kernel (task=%p, pc=%lx)\n",
 	       current, regs->nip);
 }
@@ -776,6 +813,9 @@ void altivec_unavailable_exception(struct pt_regs *regs)
 {
 	static int kernel_altivec_count;
 
+ 	if (ipipe_trap_notify(IPIPE_TRAP_ALTUNAVAIL,regs))
+ 	    	return;
+ 
 #ifndef CONFIG_ALTIVEC
 	if (user_mode(regs)) {
 		/* A user program has executed an altivec instruction,
@@ -797,6 +837,9 @@ void altivec_assist_exception(struct pt_regs *regs)
 {
 	int err;
 
+ 	if (ipipe_trap_notify(IPIPE_TRAP_ALTASSIST,regs))
+ 	    	return;
+ 
 	preempt_disable();
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
@@ -820,11 +863,14 @@ void altivec_assist_exception(struct pt_regs *regs)
 		/* got an error reading the instruction */
 		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
 	} else {
+		MARK(kernel_arch_trap_entry, "%ld %ld", regs->trap,
+			instruction_pointer(regs));
 		/* didn't recognize the instruction */
 		/* XXX quick hack for now: set the non-Java bit in the VSCR */
 		printk(KERN_ERR "unrecognized altivec instruction "
 		       "in %s at %lx\n", current->comm, regs->nip);
 		current->thread.vscr.u[3] |= 0x10000;
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 	}
 }
 #endif /* CONFIG_ALTIVEC */
@@ -844,8 +890,11 @@ void CacheLockingException(struct pt_regs *regs, unsigned long address,
 	 * as priv ops, in the future we could try to do
 	 * something smarter
 	 */
-	if (error_code & (ESR_DLK|ESR_ILK))
+	if (error_code & (ESR_DLK|ESR_ILK)) {
+		if (ipipe_trap_notify(IPIPE_TRAP_CACHE,regs))
+			return;
 		_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+	}
 	return;
 }
 #endif /* CONFIG_FSL_BOOKE */
@@ -857,6 +906,9 @@ void SPEFloatingPointException(struct pt_regs *regs)
 	int fpexc_mode;
 	int code = 0;
 
+	if (ipipe_trap_notify(IPIPE_TRAP_SPE,regs))
+	    	return;
+
 	spefscr = current->thread.spefscr;
 	fpexc_mode = current->thread.fpexc_mode;
 
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
index 6192126..f9bfd6a 100644
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -73,6 +73,7 @@ SECTIONS
     *(.sdata2)
     *(.got.plt) *(.got)
     *(.dynamic)
+    EXTRA_RWDATA
     CONSTRUCTORS
   }
 
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 465f451..ba8cdfa 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -113,6 +113,9 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
 		is_write = error_code & 0x02000000;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
+ 	if (ipipe_trap_notify(IPIPE_TRAP_ACCESS,regs))
+ 	    	return 0;
+ 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && TRAP(regs) == 0x300) {
 		debugger_fault_handler(regs);
@@ -249,16 +252,22 @@ good_area:
 	 * the fault.
 	 */
  survive:
+ 	MARK(kernel_arch_trap_entry, "%ld %ld",
+		regs->trap, instruction_pointer(regs));
         switch (handle_mm_fault(mm, vma, address, is_write)) {
         case VM_FAULT_MINOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
                 current->min_flt++;
                 break;
         case VM_FAULT_MAJOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
                 current->maj_flt++;
                 break;
         case VM_FAULT_SIGBUS:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
                 goto do_sigbus;
         case VM_FAULT_OOM:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
                 goto out_of_memory;
 	default:
 		BUG();
diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
index e756942..3daaeef 100644
--- a/arch/ppc/mm/hashtable.S
+++ b/arch/ppc/mm/hashtable.S
@@ -473,7 +473,11 @@ found_slot:
  *
  * We assume that there is a hash table in use (Hash != 0).
  */
+#ifdef CONFIG_IPIPE
+_GLOBAL(__flush_hash_pages)
+#else	
 _GLOBAL(flush_hash_pages)
+#endif	
 	tophys(r7,0)
 
 	/*
@@ -601,5 +605,5 @@ _GLOBAL(flush_hash_patch_B)
 
 19:	mtmsr	r10
 	SYNC_601
-	isync
+	sync
 	blr
diff --git a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c
index fa29740..ce16a0c 100644
--- a/arch/ppc/mm/tlb.c
+++ b/arch/ppc/mm/tlb.c
@@ -95,6 +95,37 @@ void tlb_flush(struct mmu_gather *tlb)
 #define FINISH_FLUSH	do { } while (0)
 #endif
 
+#ifdef CONFIG_IPIPE
+
+int __flush_hash_pages(unsigned context, unsigned long va,
+		       unsigned long pmdval, int count);
+
+int flush_hash_pages(unsigned context, unsigned long va,
+		     unsigned long pmdval, int count)
+{
+	int bulk, ret = 0;
+	/*
+	 * Submitting flush requests on insanely large PTE counts
+	 * (e.g. HIGHMEM) may cause severe latency penalty on high
+	 * priority domains since this must be done with hw interrupts
+	 * off (typically, peaks over 400 us have been observed on
+	 * 864xD). We split flush requests in bulks of 64 PTEs to
+	 * prevent that; the modified assembly helper which performs
+	 * the actual flush (__flush_hash_pages()) will spin on the
+	 * mmu_lock with interrupts enabled to further reduce latency.
+	 */
+	while (count > 0) {
+		bulk = count > 64 ? 64 : count;
+		ret |= __flush_hash_pages(context, va, pmdval, bulk);
+		va += (bulk << PAGE_SHIFT);
+		count -= bulk;
+	}
+
+	return ret;
+}
+
+#endif /* CONFIG_IPIPE */
+
 static void flush_range(struct mm_struct *mm, unsigned long start,
 			unsigned long end)
 {
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
index fb2d584..550b647 100644
--- a/arch/ppc/syslib/cpm2_pic.c
+++ b/arch/ppc/syslib/cpm2_pic.c
@@ -49,6 +49,7 @@ static void cpm2_mask_irq(unsigned int irq_nr)
 {
 	int	bit, word;
 	volatile uint	*simr;
+	unsigned long flags;
 
 	irq_nr -= CPM_IRQ_OFFSET;
 
@@ -56,14 +57,17 @@ static void cpm2_mask_irq(unsigned int irq_nr)
 	word = irq_to_siureg[irq_nr];
 
 	simr = &(cpm2_immr->im_intctl.ic_simrh);
+	local_irq_save_hw_cond(flags);
 	ppc_cached_irq_mask[word] &= ~(1 << bit);
 	simr[word] = ppc_cached_irq_mask[word];
+	local_irq_restore_hw_cond(flags);
 }
 
 static void cpm2_unmask_irq(unsigned int irq_nr)
 {
 	int	bit, word;
 	volatile uint	*simr;
+	unsigned long flags;
 
 	irq_nr -= CPM_IRQ_OFFSET;
 
@@ -71,14 +75,17 @@ static void cpm2_unmask_irq(unsigned int irq_nr)
 	word = irq_to_siureg[irq_nr];
 
 	simr = &(cpm2_immr->im_intctl.ic_simrh);
+	local_irq_save_hw_cond(flags);
 	ppc_cached_irq_mask[word] |= 1 << bit;
 	simr[word] = ppc_cached_irq_mask[word];
+	local_irq_restore_hw_cond(flags);
 }
 
 static void cpm2_mask_and_ack(unsigned int irq_nr)
 {
 	int	bit, word;
 	volatile uint	*simr, *sipnr;
+	unsigned long flags;
 
 	irq_nr -= CPM_IRQ_OFFSET;
 
@@ -87,17 +94,21 @@ static void cpm2_mask_and_ack(unsigned int irq_nr)
 
 	simr = &(cpm2_immr->im_intctl.ic_simrh);
 	sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
+	local_irq_save_hw_cond(flags);
 	ppc_cached_irq_mask[word] &= ~(1 << bit);
 	simr[word] = ppc_cached_irq_mask[word];
 	sipnr[word] = 1 << bit;
+	local_irq_restore_hw_cond(flags);
 }
 
 static void cpm2_end_irq(unsigned int irq_nr)
 {
 	int	bit, word;
 	volatile uint	*simr;
+	unsigned long flags;
 
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+	if (!ipipe_root_domain_p ||
+	    !(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
 			&& irq_desc[irq_nr].action) {
 
 		irq_nr -= CPM_IRQ_OFFSET;
@@ -105,8 +116,10 @@ static void cpm2_end_irq(unsigned int irq_nr)
 		word = irq_to_siureg[irq_nr];
 
 		simr = &(cpm2_immr->im_intctl.ic_simrh);
+		local_irq_save_hw_cond(flags);
 		ppc_cached_irq_mask[word] |= 1 << bit;
 		simr[word] = ppc_cached_irq_mask[word];
+		local_irq_restore_hw_cond(flags);
 		/*
 		 * Work around large numbers of spurious IRQs on PowerPC 82xx
 		 * systems.
@@ -121,6 +134,11 @@ static struct hw_interrupt_type cpm2_pic = {
 	.disable = cpm2_mask_irq,
 	.ack = cpm2_mask_and_ack,
 	.end = cpm2_end_irq,
+#ifdef CONFIG_IPIPE
+	.mask_ack	= cpm2_mask_and_ack,
+	.mask		= cpm2_mask_irq,
+	.unmask		= cpm2_unmask_irq,
+#endif
 };
 
 int cpm2_get_irq(void)
@@ -173,5 +191,9 @@ void cpm2_init_IRQ(void)
 	for (i = 0; i < NR_CPM_INTS; i++) {
 		irq_desc[i+CPM_IRQ_OFFSET].chip = &cpm2_pic;
 		irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
+#ifdef CONFIG_IPIPE
+		irq_desc[i+CPM_IRQ_OFFSET].ipipe_ack = &__ipipe_ack_level_irq;
+		irq_desc[i+CPM_IRQ_OFFSET].ipipe_end = &__ipipe_end_level_irq;
+#endif
 	}
 }
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
index 10659c2..c9a6238 100644
--- a/arch/ppc/syslib/ipic.c
+++ b/arch/ppc/syslib/ipic.c
@@ -382,40 +382,50 @@ static void ipic_enable_irq(unsigned int irq)
 {
 	struct ipic *ipic = ipic_from_irq(irq);
 	unsigned int src = irq - ipic->irq_offset;
+	unsigned long flags;
 	u32 temp;
 
+	local_irq_save_hw_cond(flags);
 	temp = ipic_read(ipic->regs, ipic_info[src].mask);
 	temp |= (1 << (31 - ipic_info[src].bit));
 	ipic_write(ipic->regs, ipic_info[src].mask, temp);
+	local_irq_restore_hw_cond(flags);
 }
 
 static void ipic_disable_irq(unsigned int irq)
 {
 	struct ipic *ipic = ipic_from_irq(irq);
 	unsigned int src = irq - ipic->irq_offset;
+	unsigned long flags;
 	u32 temp;
 
+	local_irq_save_hw_cond(flags);
 	temp = ipic_read(ipic->regs, ipic_info[src].mask);
 	temp &= ~(1 << (31 - ipic_info[src].bit));
 	ipic_write(ipic->regs, ipic_info[src].mask, temp);
+	local_irq_restore_hw_cond(flags);
 }
 
 static void ipic_disable_irq_and_ack(unsigned int irq)
 {
 	struct ipic *ipic = ipic_from_irq(irq);
 	unsigned int src = irq - ipic->irq_offset;
+	unsigned long flags;
 	u32 temp;
 
 	ipic_disable_irq(irq);
 
+	local_irq_save_hw_cond(flags);
 	temp = ipic_read(ipic->regs, ipic_info[src].pend);
 	temp |= (1 << (31 - ipic_info[src].bit));
 	ipic_write(ipic->regs, ipic_info[src].pend, temp);
+	local_irq_restore_hw_cond(flags);
 }
 
 static void ipic_end_irq(unsigned int irq)
 {
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+	if (!ipipe_root_domain_p ||
+	    !(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
 		ipic_enable_irq(irq);
 }
 
@@ -425,6 +435,11 @@ struct hw_interrupt_type ipic = {
 	.disable = ipic_disable_irq,
 	.ack = ipic_disable_irq_and_ack,
 	.end = ipic_end_irq,
+#ifdef CONFIG_IPIPE
+	.mask_ack = ipic_disable_irq_and_ack,
+	.mask = ipic_disable_irq,
+	.unmask = ipic_enable_irq,
+#endif
 };
 
 void __init ipic_init(phys_addr_t phys_addr,
@@ -474,6 +489,10 @@ void __init ipic_init(phys_addr_t phys_addr,
 	for (i = 0 ; i < NR_IPIC_INTS ; i++) {
 		irq_desc[i+irq_offset].chip = &ipic;
 		irq_desc[i+irq_offset].status = IRQ_LEVEL;
+#ifdef CONFIG_IPIPE
+		irq_desc[i+irq_offset].ipipe_ack = &__ipipe_ack_level_irq;
+		irq_desc[i+irq_offset].ipipe_end = &__ipipe_end_level_irq;
+#endif
 	}
 
 	temp = 0;
@@ -496,6 +515,7 @@ int ipic_set_priority(unsigned int irq, unsigned int priority)
 {
 	struct ipic *ipic = ipic_from_irq(irq);
 	unsigned int src = irq - ipic->irq_offset;
+	unsigned long flags;
 	u32 temp;
 
 	if (priority > 7)
@@ -505,6 +525,8 @@ int ipic_set_priority(unsigned int irq, unsigned int priority)
 	if (ipic_info[src].prio == 0)
 		return -EINVAL;
 
+	local_irq_save_hw_cond(flags);
+
 	temp = ipic_read(ipic->regs, ipic_info[src].prio);
 
 	if (priority < 4) {
@@ -517,6 +539,8 @@ int ipic_set_priority(unsigned int irq, unsigned int priority)
 
 	ipic_write(ipic->regs, ipic_info[src].prio, temp);
 
+	local_irq_restore_hw_cond(flags);
+
 	return 0;
 }
 
@@ -524,8 +548,11 @@ void ipic_set_highest_priority(unsigned int irq)
 {
 	struct ipic *ipic = ipic_from_irq(irq);
 	unsigned int src = irq - ipic->irq_offset;
+	unsigned long flags;
 	u32 temp;
 
+	local_irq_save_hw_cond(flags);
+
 	temp = ipic_read(ipic->regs, IPIC_SICFR);
 
 	/* clear and set HPI */
@@ -533,6 +560,8 @@ void ipic_set_highest_priority(unsigned int irq)
 	temp |= (src & 0x7f) << 24;
 
 	ipic_write(ipic->regs, IPIC_SICFR, temp);
+
+	local_irq_restore_hw_cond(flags);
 }
 
 void ipic_set_default_priority(void)
diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c
index af35a31..d114475 100644
--- a/arch/ppc/syslib/mpc52xx_pic.c
+++ b/arch/ppc/syslib/mpc52xx_pic.c
@@ -37,8 +37,11 @@ static struct mpc52xx_sdma __iomem *sdma;
 static void
 mpc52xx_ic_disable(unsigned int irq)
 {
+	unsigned long flags;
 	u32 val;
 
+	local_irq_save_hw_cond(flags);
+
 	if (irq == MPC52xx_IRQ0) {
 		val = in_be32(&intr->ctrl);
 		val &= ~(1 << 11);
@@ -67,13 +70,18 @@ mpc52xx_ic_disable(unsigned int irq)
 		val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
 		out_be32(&intr->per_mask, val);
 	}
+
+	local_irq_restore_hw_cond(flags);
 }
 
 static void
 mpc52xx_ic_enable(unsigned int irq)
 {
+	unsigned long flags;
 	u32 val;
 
+	local_irq_save_hw_cond(flags);
+
 	if (irq == MPC52xx_IRQ0) {
 		val = in_be32(&intr->ctrl);
 		val |= 1 << 11;
@@ -102,6 +110,8 @@ mpc52xx_ic_enable(unsigned int irq)
 		val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
 		out_be32(&intr->per_mask, val);
 	}
+
+	local_irq_restore_hw_cond(flags);
 }
 
 static void
@@ -152,14 +162,19 @@ mpc52xx_ic_ack(unsigned int irq)
 static void
 mpc52xx_ic_disable_and_ack(unsigned int irq)
 {
+	unsigned long flags;
+
+	local_irq_save_hw_cond(flags);
 	mpc52xx_ic_disable(irq);
 	mpc52xx_ic_ack(irq);
+	local_irq_restore_hw_cond(flags);
 }
 
 static void
 mpc52xx_ic_end(unsigned int irq)
 {
-	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+	if (!ipipe_root_domain_p ||
+	    (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))))
 		mpc52xx_ic_enable(irq);
 }
 
@@ -169,6 +184,11 @@ static struct hw_interrupt_type mpc52xx_ic = {
 	.disable	= mpc52xx_ic_disable,
 	.ack		= mpc52xx_ic_disable_and_ack,
 	.end		= mpc52xx_ic_end,
+#ifdef CONFIG_IPIPE
+	.mask_ack = mpc52xx_ic_disable_and_ack,
+	.mask = mpc52xx_ic_disable,
+	.unmask = mpc52xx_ic_enable,
+#endif
 };
 
 void __init
@@ -208,6 +228,10 @@ mpc52xx_init_irq(void)
 	for (i = 0; i < NR_IRQS; i++) {
 		irq_desc[i].chip = &mpc52xx_ic;
 		irq_desc[i].status = IRQ_LEVEL;
+#ifdef CONFIG_IPIPE
+		irq_desc[i].ipipe_ack = &__ipipe_ack_level_irq;
+		irq_desc[i].ipipe_end = &__ipipe_end_level_irq;
+#endif
 	}
 
 	#define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03)
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
index 18ec947..bd3fcd0 100644
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -90,6 +90,11 @@ struct hw_interrupt_type open_pic = {
 	.enable		= openpic_enable_irq,
 	.disable	= openpic_disable_irq,
 	.ack		= openpic_ack_irq,
+#ifdef CONFIG_IPIPE
+	.mask_ack	= openpic_ack_irq,
+	.mask		= openpic_disable_irq,
+	.unmask		= openpic_enable_irq,
+#endif
 	.end		= openpic_end_irq,
 	.set_affinity	= openpic_set_affinity,
 };
@@ -406,8 +411,14 @@ void __init openpic_init(int offset)
 	}
 
 	/* Init descriptors */
-	for (i = offset; i < NumSources + offset; i++)
+	for (i = offset; i < NumSources + offset; i++) {
 		irq_desc[i].chip = &open_pic;
+#ifdef CONFIG_IPIPE
+		/* We want mask_ack/unmask for all. */
+		irq_desc[i].ipipe_ack = &__ipipe_ack_level_irq;
+		irq_desc[i].ipipe_end = &__ipipe_end_level_irq;
+#endif
+	}
 
 	/* Initialize the spurious interrupt */
 	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
@@ -718,29 +729,35 @@ openpic_hookup_cascade(u_int irq, char *name,
 static void openpic_enable_irq(u_int irq)
 {
 	volatile u_int __iomem *vpp;
+	unsigned long flags;
 
 	check_arg_irq(irq);
 	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
+	local_irq_save_hw_cond(flags);
 	openpic_clearfield(vpp, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
 		mb(); /* sync is probably useless here */
 	} while (openpic_readfield(vpp, OPENPIC_MASK));
+	local_irq_restore_hw_cond(flags);
 }
 
 static void openpic_disable_irq(u_int irq)
 {
 	volatile u_int __iomem *vpp;
+	unsigned long flags;
 	u32 vp;
 
 	check_arg_irq(irq);
 	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
+	local_irq_save_hw_cond(flags);
 	openpic_setfield(vpp, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
 		mb();  /* sync is probably useless here */
 		vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
 	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
+	local_irq_restore_hw_cond(flags);
 }
 
 #ifdef CONFIG_SMP
@@ -821,7 +838,7 @@ static void openpic_set_sense(u_int irq, int sense)
  */
 static void openpic_ack_irq(unsigned int irq_nr)
 {
-#ifdef __SLOW_VERSION__
+#if defined(__SLOW_VERSION__) || defined(CONFIG_IPIPE)
 	openpic_disable_irq(irq_nr);
 	openpic_eoi();
 #else
@@ -832,9 +849,10 @@ static void openpic_ack_irq(unsigned int irq_nr)
 
 static void openpic_end_irq(unsigned int irq_nr)
 {
-#ifdef __SLOW_VERSION__
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-	    && irq_desc[irq_nr].action)
+#if defined(__SLOW_VERSION__) || defined(CONFIG_IPIPE)
+	if (!ipipe_root_domain_p ||
+	    (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+	     && irq_desc[irq_nr].action))
 		openpic_enable_irq(irq_nr);
 #else
 	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
index ee0da4b..9490fab 100644
--- a/arch/ppc/syslib/ppc4xx_pic.c
+++ b/arch/ppc/syslib/ppc4xx_pic.c
@@ -41,40 +41,52 @@ extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak));
 static void ppc4xx_uic##n##_enable(unsigned int irq)			\
 {									\
 	u32 mask = IRQ_MASK_UIC##n(irq);				\
+	unsigned long flags;						\
+	local_irq_save_hw_cond(flags);					\
 	if (irq_desc[irq].status & IRQ_LEVEL)				\
 		mtdcr(DCRN_UIC_SR(UIC##n), mask);			\
 	ppc_cached_irq_mask[n] |= mask;					\
 	mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);		\
+	local_irq_restore_hw_cond(flags);				\
 }									\
 									\
 static void ppc4xx_uic##n##_disable(unsigned int irq)			\
 {									\
+	unsigned long flags;						\
+	local_irq_save_hw_cond(flags);					\
 	ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq);		\
 	mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);		\
 	ACK_UIC##n##_PARENT						\
+	local_irq_restore_hw_cond(flags);				\
 }									\
 									\
 static void ppc4xx_uic##n##_ack(unsigned int irq)			\
 {									\
 	u32 mask = IRQ_MASK_UIC##n(irq);				\
+	unsigned long flags;						\
+	local_irq_save_hw_cond(flags);					\
 	ppc_cached_irq_mask[n] &= ~mask;				\
 	mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);		\
 	mtdcr(DCRN_UIC_SR(UIC##n), mask);				\
 	ACK_UIC##n##_PARENT						\
+	local_irq_restore_hw_cond(flags);				\
 }									\
 									\
 static void ppc4xx_uic##n##_end(unsigned int irq)			\
 {									\
 	unsigned int status = irq_desc[irq].status;			\
 	u32 mask = IRQ_MASK_UIC##n(irq);				\
+	unsigned long flags;						\
+	local_irq_save_hw_cond(flags);					\
 	if (status & IRQ_LEVEL) {					\
 		mtdcr(DCRN_UIC_SR(UIC##n), mask);			\
 		ACK_UIC##n##_PARENT					\
 	}								\
-	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {		\
+	if (!ipipe_root_domain_p || !(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {		\
 		ppc_cached_irq_mask[n] |= mask;				\
 		mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);	\
 	}								\
+	local_irq_restore_hw_cond(flags);				\
 }
 
 #define DECLARE_UIC(n)							\
@@ -84,6 +96,8 @@ static void ppc4xx_uic##n##_end(unsigned int irq)			\
 	.disable 	= ppc4xx_uic##n##_disable,			\
 	.ack 		= ppc4xx_uic##n##_ack,				\
 	.end 		= ppc4xx_uic##n##_end,				\
+	.mask 		= ppc4xx_uic##n##_disable,			\
+	.unmask		= ppc4xx_uic##n##_enable,			\
 }									\
 
 #if NR_UICS == 4
@@ -278,6 +292,11 @@ void __init ppc4xx_pic_init(void)
 		irq_desc[i].chip = &__uic[i >> 5].decl;
 		if (is_level_sensitive(i))
 			irq_desc[i].status |= IRQ_LEVEL;
+#ifdef CONFIG_IPIPE
+		/* We want mask_ack/unmask for all. */
+		irq_desc[i].ipipe_ack = &__ipipe_ack_level_irq;
+		irq_desc[i].ipipe_end = &__ipipe_end_level_irq;
+#endif
 	}
 
 	ppc_md.get_irq = ppc4xx_pic_get_irq;
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1227236..56668ca 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -518,6 +518,10 @@ config KPROBES
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
 endmenu
 
 source "arch/s390/Kconfig.debug"
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index 584ed95..406b994 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -150,6 +150,8 @@ asmlinkage long sys_ipc(uint call, int first, unsigned long second,
         struct ipc_kludge tmp;
 	int ret;
 
+        MARK(ipc_call, "%u %d", call, first);
+
         switch (call) {
         case SEMOP:
 		return sys_semtimedop(first, (struct sembuf __user *)ptr,
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 3cbb0dc..7bbeb70 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -5,6 +5,7 @@
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *  Portions added by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation
  *
  *  Derived from "arch/i386/kernel/traps.c"
  *    Copyright (C) 1991, 1992 Linus Torvalds
@@ -333,6 +334,9 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
 				interruption_code, signr) == NOTIFY_STOP)
 		return;
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		interruption_code & 0xffff, regs);
+
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;
 
@@ -347,6 +351,7 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
                 else
                         die(str, regs, interruption_code);
         }
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
 
 static inline void __user *get_check_address(struct pt_regs *regs)
@@ -458,6 +463,9 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 	if (regs->psw.mask & PSW_MASK_PSTATE)
 		local_irq_enable();
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		interruption_code & 0xffff, regs);
+
 	if (regs->psw.mask & PSW_MASK_PSTATE) {
 		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
 			return;
@@ -515,6 +523,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 		do_trap(interruption_code, signal,
 			"illegal operation", regs, &info);
 	}
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
 
 
@@ -535,6 +544,9 @@ specification_exception(struct pt_regs * regs, long interruption_code)
         if (regs->psw.mask & PSW_MASK_PSTATE)
 		local_irq_enable();
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		interruption_code & 0xffff, regs);
+
         if (regs->psw.mask & PSW_MASK_PSTATE) {
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
@@ -579,6 +591,7 @@ specification_exception(struct pt_regs * regs, long interruption_code)
 		do_trap(interruption_code, signal, 
 			"specification exception", regs, &info);
 	}
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
 #else
 DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
@@ -599,6 +612,9 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 	if (regs->psw.mask & PSW_MASK_PSTATE)
 		local_irq_enable();
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		interruption_code & 0xffff, regs);
+
 	if (MACHINE_HAS_IEEE)
 		asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
 
@@ -673,6 +689,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 		do_trap(interruption_code, signal, 
 			"data exception", regs, &info);
 	}
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
 
 asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index fe0f2e9..f51ff5f 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -46,6 +46,7 @@ SECTIONS
 
   .data : {			/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	}
 
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index cd85e34..b94c6e7 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -5,6 +5,7 @@
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com)
  *               Ulrich Weigand (uweigand@de.ibm.com)
+ *  Portions added by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation
  *
  *  Derived from "arch/i386/mm/fault.c"
  *    Copyright (C) 1995  Linus Torvalds
@@ -255,6 +256,9 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
 	 */
 	local_irq_enable();
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		error_code & 0xffff, regs);
+
         down_read(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
@@ -322,6 +326,7 @@ bad_area:
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
 		do_sigsegv(regs, error_code, si_code, address);
+		MARK(kernel_trap_exit, MARK_NOARGS);
                 return;
 	}
 
@@ -378,6 +383,8 @@ do_sigbus:
 	/* Kernel mode? Handle exceptions or die */
 	if (!(regs->psw.mask & PSW_MASK_PSTATE))
 		goto no_context;
+
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
 
 void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 3aa3b88..eb9abf5 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -707,6 +707,14 @@ source "fs/Kconfig"
 
 source "arch/sh/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/sh/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index fc279ae..fc54fe9 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -279,7 +279,7 @@ work_resched:
 syscall_exit_work:
 	! r0: current_thread_info->flags
 	! r8: current_thread_info
-	tst	#_TIF_SYSCALL_TRACE, r0
+	tst	#(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT), r0
 	bt/s	work_pending
 	 tst	#_TIF_NEED_RESCHED, r0
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -399,7 +399,7 @@ ENTRY(system_call)
 	!
 	get_current_thread_info r8, r10
 	mov.l	@(TI_FLAGS,r8), r8
-	mov	#_TIF_SYSCALL_TRACE, r10
+	mov	#(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT), r10
 	tst	r10, r8
 	bf	syscall_trace_entry
 	!
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 67be2b6..72ff8ec 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -13,6 +13,7 @@
 #include <linux/seq_file.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/thread_info.h>
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 486c06e..d909e87 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -154,6 +154,7 @@ __asm__(".align 5\n"
 
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
+	unsigned long pid;
 	struct pt_regs regs;
 
 	memset(&regs, 0, sizeof(regs));
@@ -164,7 +165,9 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 	regs.sr = (1 << 30);
 
 	/* Ok, create the new process.. */
-	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+	pid =  do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+	MARK(kernel_thread_create, "%ld %p", pid, fn);
+	return pid;
 }
 
 /*
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index e18f183..44de6a4 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -23,6 +23,7 @@
 #include <linux/utsname.h>
 #include <linux/module.h>
 #include <asm/cacheflush.h>
+
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 #include <asm/unistd.h>
@@ -192,6 +193,8 @@ asmlinkage int sys_ipc(uint call, int first, int second,
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
+	MARK(ipc_call, "%u %d", call, first);
+
 	if (call <= SEMCTL)
 		switch (call) {
 		case SEMOP:
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index ec11015..75c8e9f 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/debug_locks.h>
 #include <linux/limits.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
@@ -564,6 +565,8 @@ asmlinkage void do_address_error(struct pt_regs *regs,
 	lookup_exception_vector(error_code);
 #endif
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		error_code >> 5, regs);
 	oldfs = get_fs();
 
 	if (user_mode(regs)) {
@@ -590,8 +593,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
 		tmp = handle_unaligned_access(instruction, regs);
 		set_fs(oldfs);
 
-		if (tmp==0)
-			return; /* sorted */
+		if (tmp==0) {
+			MARK(kernel_trap_exit, MARK_NOARGS);
+ 			return; /* sorted */
+		}
 #endif
 
 uspace_segv:
@@ -627,6 +632,7 @@ uspace_segv:
 		force_sig(SIGSEGV, current);
 #endif
 	}
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
 
 #ifdef CONFIG_SH_DSP
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index f34bdcc..b48e84f 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -39,6 +39,7 @@ SECTIONS
 
   .data : {			/* Data */
 	*(.data)
+	EXTRA_RWDATA
 
  	 /* Align the initial ramdisk image (INITRD) on page boundaries. */
  	 . = ALIGN(PAGE_SIZE);
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index 716ebf5..3baf4a2 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
+
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/kgdb.h>
@@ -88,6 +89,14 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
 		return;
 	}
 
+	MARK(kernel_trap_entry, "%lu %p[struct pt_regs]",
+		({
+			unsigned long trapnr; 
+			asm volatile("stc	r2_bank,%0": "=r" (trapnr));
+			trapnr;
+		}) >> 5,
+		regs);
+
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
@@ -142,6 +151,7 @@ survive:
 	}
 
 	up_read(&mm->mmap_sem);
+	MARK(kernel_trap_exit, MARK_NOARGS);
 	return;
 
 /*
@@ -158,6 +168,7 @@ bad_area_nosemaphore:
 		info.si_code = si_code;
 		info.si_addr = (void *) address;
 		force_sig_info(SIGSEGV, &info, tsk);
+		MARK(kernel_trap_exit, MARK_NOARGS);
 		return;
 	}
 
@@ -223,4 +234,6 @@ do_sigbus:
 	/* Kernel mode? Handle exceptions or die */
 	if (!user_mode(regs))
 		goto no_context;
+
+	MARK(kernel_trap_exit, MARK_NOARGS);
 }
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
index 7bc0744..04edbbd 100644
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -284,6 +284,14 @@ source "fs/Kconfig"
 
 source "arch/sh64/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/sh64/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/sh64/kernel/entry.S b/arch/sh64/kernel/entry.S
index 40d4534..c81d7bb 100644
--- a/arch/sh64/kernel/entry.S
+++ b/arch/sh64/kernel/entry.S
@@ -1282,7 +1282,7 @@ syscall_allowed:
 
 	getcon	KCR0, r2
 	ld.l	r2, TI_FLAGS, r4
-	movi	(1 << TIF_SYSCALL_TRACE), r6
+	movi	((1 << TIF_SYSCALL_TRACE) | (1 << TIF_SYSCALL_AUDIT)), r6
 	and	r6, r4, r6
 	beq/l	r6, ZERO, tr0
 
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index 95c4d75..14b6145 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -79,6 +79,7 @@ SECTIONS
 
   .data : C_PHYS(.data) {			/* Data */
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	}
 
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index d0dec1e..75d142b 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -302,6 +302,10 @@ menu "Instrumentation Support"
 
 source "arch/sparc/oprofile/Kconfig"
 
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
 endmenu
 
 source "arch/sparc/Kconfig.debug"
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 831f540..422e92d 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1232,7 +1232,7 @@ sys_ptrace:
 	 add	%sp, STACKFRAME_SZ, %o0
 
 	ld	[%curptr + TI_FLAGS], %l5
-	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
+	andcc	%l5, (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %g0
 	be	1f
 	 nop
 
@@ -1281,7 +1281,7 @@ sys_sigreturn:
 	 add	%sp, STACKFRAME_SZ, %o0
 
 	ld	[%curptr + TI_FLAGS], %l5
-	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
+	andcc	%l5, (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %g0
 	be	1f
 	 nop
 
@@ -1301,7 +1301,7 @@ sys_rt_sigreturn:
 	 add	%sp, STACKFRAME_SZ, %o0
 
 	ld	[%curptr + TI_FLAGS], %l5
-	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
+	andcc	%l5, (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %g0
 	be	1f
 	 nop
 
@@ -1437,7 +1437,7 @@ syscall_is_too_hard:
 
 	ld	[%curptr + TI_FLAGS], %l5
 	mov	%i3, %o3
-	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
+	andcc	%l5, (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %g0
 	mov	%i4, %o4
 	bne	linux_syscall_trace
 	 mov	%i0, %l5
@@ -1454,7 +1454,7 @@ ret_sys_call:
 	ld	[%sp + STACKFRAME_SZ + PT_PSR], %g3
 	set	PSR_C, %g2
 	bgeu	1f
-	 andcc	%l6, _TIF_SYSCALL_TRACE, %g0
+	 andcc	%l6, (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %g0
 
 	/* System call success, clear Carry condition code. */
 	andn	%g3, %g2, %g3
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 113bd48..9231ed5 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -348,7 +348,7 @@ void exit_thread(void)
 #ifndef CONFIG_SMP
 	if(last_task_used_math == current) {
 #else
-	if(current_thread_info()->flags & _TIF_USEDFPU) {
+	if(test_ti_thread_flag(current_thread_info(), TIF_USEDFPU)) {
 #endif
 		/* Keep process from leaving FPU in a bogon state. */
 		put_psr(get_psr() | PSR_EF);
@@ -357,7 +357,7 @@ void exit_thread(void)
 #ifndef CONFIG_SMP
 		last_task_used_math = NULL;
 #else
-		current_thread_info()->flags &= ~_TIF_USEDFPU;
+		clear_ti_thread_flag(current_thread_info(), TIF_USEDFPU);
 #endif
 	}
 }
@@ -371,7 +371,7 @@ void flush_thread(void)
 #ifndef CONFIG_SMP
 	if(last_task_used_math == current) {
 #else
-	if(current_thread_info()->flags & _TIF_USEDFPU) {
+	if(test_ti_thread_flag(current_thread_info(), TIF_USEDFPU)) {
 #endif
 		/* Clean the fpu. */
 		put_psr(get_psr() | PSR_EF);
@@ -380,7 +380,7 @@ void flush_thread(void)
 #ifndef CONFIG_SMP
 		last_task_used_math = NULL;
 #else
-		current_thread_info()->flags &= ~_TIF_USEDFPU;
+		clear_ti_thread_flag(current_thread_info(), TIF_USEDFPU);
 #endif
 	}
 
@@ -466,13 +466,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
 #ifndef CONFIG_SMP
 	if(last_task_used_math == current) {
 #else
-	if(current_thread_info()->flags & _TIF_USEDFPU) {
+	if(test_ti_thread_flag(current_thread_info(), TIF_USEDFPU)) {
 #endif
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&p->thread.float_regs[0], &p->thread.fsr,
 		       &p->thread.fpqueue[0], &p->thread.fpqdepth);
 #ifdef CONFIG_SMP
-		current_thread_info()->flags &= ~_TIF_USEDFPU;
+		clear_ti_thread_flag(current_thread_info(), TIF_USEDFPU);
 #endif
 	}
 
@@ -609,13 +609,14 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 		return 1;
 	}
 #ifdef CONFIG_SMP
-	if (current_thread_info()->flags & _TIF_USEDFPU) {
+	if (test_ti_thread_flag(current_thread_info(), TIF_USEDFPU)) {
 		put_psr(get_psr() | PSR_EF);
 		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
 		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
 		if (regs != NULL) {
 			regs->psr &= ~(PSR_EF);
-			current_thread_info()->flags &= ~(_TIF_USEDFPU);
+			clear_ti_thread_flag(current_thread_info(),
+				TIF_USEDFPU);
 		}
 	}
 #else
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 6a70d21..8ec8d08 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -259,7 +259,7 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 	} else {
 		fpload(&current->thread.float_regs[0], &current->thread.fsr);
 	}
-	current_thread_info()->flags |= _TIF_USEDFPU;
+	set_ti_thread_flag(current_thread_info(), TIF_USEDFPU);
 #endif
 }
 
@@ -290,7 +290,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 #ifndef CONFIG_SMP
 	if(!fpt) {
 #else
-        if(!(task_thread_info(fpt)->flags & _TIF_USEDFPU)) {
+        if(!test_ti_thread_flag(task_thread_info(fpt), TIF_USEDFPU)) {
 #endif
 		fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
 		regs->psr &= ~PSR_EF;
@@ -333,7 +333,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 	/* nope, better SIGFPE the offending process... */
 	       
 #ifdef CONFIG_SMP
-	task_thread_info(fpt)->flags &= ~_TIF_USEDFPU;
+	clear_tsk_thread_flag(fpt, TIF_USEDFPU);
 #endif
 	if(psr & PSR_PS) {
 		/* The first fsr store/load we tried trapped,
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index b73e6b9..619a06f 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -23,6 +23,7 @@ SECTIONS
   .data    :
   {
     *(.data)
+    EXTRA_RWDATA
     CONSTRUCTORS
   }
   .data1   : { *(.data1) }
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index d41f66a..5465a41 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -443,6 +443,11 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
 endmenu
 
 source "arch/sparc64/Kconfig.debug"
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 7d75cd4..b291060 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -413,8 +413,13 @@ void flush_thread(void)
 	struct thread_info *t = current_thread_info();
 	struct mm_struct *mm;
 
-	if (t->flags & _TIF_ABI_PENDING)
-		t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
+	if (test_ti_thread_flag(t, TIF_ABI_PENDING)) {
+		clear_ti_thread_flag(t, TIF_ABI_PENDING);
+		if (test_ti_thread_flag(t, TIF_32BIT))
+			clear_ti_thread_flag(t, TIF_32BIT);
+		else
+			set_ti_thread_flag(t, TIF_32BIT);
+	}
 
 	mm = t->task->mm;
 	if (mm)
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 4a6063f..94b1a78 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -28,6 +28,7 @@ SECTIONS
   .data    :
   {
     *(.data)
+    EXTRA_RWDATA
     CONSTRUCTORS
   }
   .data1   : { *(.data1) }
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index d32a80e..2e8ada0 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -344,4 +344,12 @@ config INPUT
 	bool
 	default n
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/um/Kconfig.debug"
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index e36f92b..1c5b5ca 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -98,6 +98,7 @@ SECTIONS
     . = ALIGN(KERNEL_STACK_SIZE);		/* init_task */
     *(.data.init_task)
     *(.data .data.* .gnu.linkonce.d.*)
+    EXTRA_RWDATA
     SORT(CONSTRUCTORS)
   }
   .data1          : { *(.data1) }
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index f630127..7b8748d 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -61,6 +61,7 @@ SECTIONS
     *(.data.init_task)
     *(.data)
     *(.gnu.linkonce.d*)
+    EXTRA_RWDATA
     CONSTRUCTORS
   }
   .data1   : { *(.data1) }
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index f0d4d72..0a7be72 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -332,6 +332,14 @@ source "sound/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/v850/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S
index 3a5fd07..26a51eb 100644
--- a/arch/v850/kernel/vmlinux.lds.S
+++ b/arch/v850/kernel/vmlinux.lds.S
@@ -116,6 +116,7 @@
         	*(.data)						      \
 			*(.exit.data)	/* 2.5 convention */		      \
 			*(.data.exit)	/* 2.4 convention */		      \
+		EXTRA_RWDATA						      \
 		. = ALIGN (16) ;					      \
 		*(.data.cacheline_aligned)				      \
 		. = ALIGN (0x2000) ;					      \
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index d427553..99d9cea 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -731,6 +731,11 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
 endmenu
 
 source "arch/x86_64/Kconfig.debug"
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index b4aa875..0fcd7ad 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -714,8 +714,10 @@ ia32_sys_call_table:
 	.quad compat_sys_get_robust_list
 	.quad sys_splice
 	.quad sys_sync_file_range
-	.quad sys_tee
+	.quad sys_tee			/* 315 */
 	.quad compat_sys_vmsplice
 	.quad compat_sys_move_pages
 	.quad sys_getcpu
+	.quad sys_ltt_trace_generic
+	.quad sys_ltt_register_generic	/* 320 */
 ia32_syscall_end:		
diff --git a/arch/x86_64/ia32/ipc32.c b/arch/x86_64/ia32/ipc32.c
index 369151d..c8e96e6 100644
--- a/arch/x86_64/ia32/ipc32.c
+++ b/arch/x86_64/ia32/ipc32.c
@@ -20,6 +20,8 @@ sys32_ipc(u32 call, int first, int second, int third,
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
+	MARK(kernel_arch_ipc_call, "%u %d", call, first);
+
 	switch (call) {
 	      case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 9f5dac6..04c18f0 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -938,7 +938,7 @@ bad_gs:
  * asm input arguments:
  *	rdi: fn, rsi: arg, rdx: flags
  */
-ENTRY(kernel_thread)
+ENTRY(kernel_thread_asm)
 	CFI_STARTPROC
 	FAKE_STACK_FRAME $child_rip
 	SAVE_ALL
diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c
index 3dc5854..d78a611 100644
--- a/arch/x86_64/kernel/init_task.c
+++ b/arch/x86_64/kernel/init_task.c
@@ -50,5 +50,6 @@ DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_sm
  * debugging, no special alignment required.
  */
 DEFINE_PER_CPU(struct orig_ist, orig_ist);
+EXPORT_PER_CPU_SYMBOL_GPL(orig_ist);
 
 #define ALIGN_TO_4K __attribute__((section(".data.init_task")))
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index cbbc6ad..0a765a1 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -54,6 +54,9 @@
 
 asmlinkage extern void ret_from_fork(void);
 
+asmlinkage long kernel_thread_asm(int (*fn)(void *), void * arg,
+	 unsigned long flags);
+
 unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
 
 unsigned long boot_option_idle_override = 0;
@@ -382,14 +385,17 @@ void exit_thread(void)
 void flush_thread(void)
 {
 	struct task_struct *tsk = current;
-	struct thread_info *t = current_thread_info();
 
-	if (t->flags & _TIF_ABI_PENDING) {
-		t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
-		if (t->flags & _TIF_IA32)
+	if (test_tsk_thread_flag(tsk, TIF_ABI_PENDING)) {
+		clear_tsk_thread_flag(tsk, TIF_ABI_PENDING);
+		if (test_tsk_thread_flag(tsk, TIF_IA32)) {
+			clear_tsk_thread_flag(tsk, TIF_IA32);
+		} else {
+			set_tsk_thread_flag(tsk, TIF_IA32);
 			current_thread_info()->status |= TS_COMPAT;
+		}
 	}
-	t->flags &= ~_TIF_DEBUG;
+	clear_tsk_thread_flag(tsk, TIF_DEBUG);
 
 	tsk->thread.debugreg0 = 0;
 	tsk->thread.debugreg1 = 0;
@@ -885,3 +891,11 @@ unsigned long arch_align_stack(unsigned long sp)
 		sp -= get_random_int() % 8192;
 	return sp & ~0xf;
 }
+
+asmlinkage long kernel_thread(int (*fn)(void *), void * arg,
+	 unsigned long flags)
+{
+	long pid = kernel_thread_asm(fn, arg, flags);
+	MARK(kernel_arch_kthread_create, "%ld %p", pid, fn);
+	return pid;
+}
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index addc14a..7ed495c 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -596,6 +596,12 @@ static void syscall_trace(struct pt_regs *regs)
 
 asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 {
+	MARK(kernel_arch_syscall_entry, "%d %ld",
+		(int)regs->orig_rax, instruction_pointer(regs));
+	MARK(stack_arch_syscall_dump_kernel_stack, MARK_NOARGS, regs);
+	MARK(stack_arch_syscall_dump_process32_stack, MARK_NOARGS, regs);
+	MARK(stack_arch_syscall_dump_process64_stack, MARK_NOARGS, regs);
+
 	/* do the secure computing check first */
 	secure_computing(regs->orig_rax);
 
@@ -620,6 +626,8 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
+	MARK(kernel_arch_syscall_exit, MARK_NOARGS);
+
 	if (unlikely(current->audit_context))
 		audit_syscall_exit(AUDITSC_RESULT(regs->rax), regs->rax);
 
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 5cc76d0..d11db6a 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -39,6 +39,7 @@
 #include <asm/proto.h>
 #include <asm/hpet.h>
 #include <asm/sections.h>
+#include <asm/ltt.h>
 #include <linux/cpufreq.h>
 #include <linux/hpet.h>
 #include <asm/apic.h>
@@ -302,6 +303,47 @@ unsigned long long monotonic_clock(void)
 }
 EXPORT_SYMBOL(monotonic_clock);
 
+/* ltt_monotonic_clock(): returns # of nanoseconds passed since time_init()
+ *		Note: This function is required to return accurate
+ *		time even in the absence of multiple timer ticks.
+ *		This function supports being nested over the write seqlock : it
+ *		will simply fail by returning 0. Useful for NMI tracing and
+ *		lockdep tracing.
+ */
+unsigned long long ltt_monotonic_clock(void)
+{
+	unsigned long seq;
+ 	u32 last_offset, this_offset, offset;
+	unsigned long long base;
+	unsigned long try = 5;
+
+	if (vxtime.mode == VXTIME_HPET) {
+		do {
+			seq = read_seqbegin(&xtime_lock);
+
+			last_offset = vxtime.last;
+			base = monotonic_base;
+			this_offset = hpet_readl(HPET_COUNTER);
+		} while (read_seqretry(&xtime_lock, seq) && (--try) > 0);
+		offset = (this_offset - last_offset);
+		offset *= NSEC_PER_TICK / hpet_tick;
+	} else {
+		do {
+			seq = read_seqbegin(&xtime_lock);
+
+			last_offset = vxtime.last_tsc;
+			base = monotonic_base;
+		} while (read_seqretry(&xtime_lock, seq) && (--try) > 0);
+		this_offset = get_cycles_sync();
+		offset = cycles_2_ns(this_offset - last_offset);
+	}
+	if (try == 0)
+		return 0;
+	else
+		return base + offset;
+}
+EXPORT_SYMBOL(ltt_monotonic_clock);
+
 static noinline void handle_lost_ticks(int lost)
 {
 	static long lost_count;
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 09d2e8a..4a0c67a 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -584,6 +584,9 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
 	tsk->thread.error_code = error_code;
 	tsk->thread.trap_no = trapnr;
 
+	MARK(kernel_arch_trap_entry, "%d %ld", trapnr,
+		instruction_pointer(regs));
+
 	if (user_mode(regs)) {
 		if (exception_trace && unhandled_signal(tsk, signr))
 			printk(KERN_INFO
@@ -595,6 +598,7 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
 			force_sig_info(signr, info, tsk);
 		else
 			force_sig(signr, tsk);
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return;
 	}
 
@@ -607,8 +611,10 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
 			regs->rip = fixup->fixup;
 		else	
 			die(str, regs, error_code);
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return;
 	}
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 #define DO_ERROR(trapnr, signr, str, name) \
@@ -692,7 +698,10 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
 			       tsk->comm, tsk->pid,
 			       regs->rip, regs->rsp, error_code); 
 
+		MARK(kernel_arch_trap_entry, "%d %ld", 13,
+			instruction_pointer(regs));
 		force_sig(SIGSEGV, tsk);
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return;
 	} 
 
@@ -762,6 +771,9 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
 	unsigned char reason = 0;
 	int cpu;
 
+	MARK(kernel_arch_trap_entry, "%d %ld", 2, instruction_pointer(regs));
+	MARK(stack_arch_nmi_dump_kernel_stack, MARK_NOARGS, regs);
+
 	cpu = smp_processor_id();
 
 	/* Only the BSP gets external NMIs from the system.  */
@@ -770,21 +782,28 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
 
 	if (!(reason & 0xc0)) {
 		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-								== NOTIFY_STOP)
+								== NOTIFY_STOP) {
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			return;
+		}
 		/*
 		 * Ok, so this is none of the documented NMI sources,
 		 * so it must be the NMI watchdog.
 		 */
-		if (nmi_watchdog_tick(regs,reason))
+		if (nmi_watchdog_tick(regs,reason)) {
+			MARK(kernel_arch_trap_exit, MARK_NOARGS);
 			return;
+		}
 		if (!do_nmi_callback(regs,cpu))
 			unknown_nmi_error(reason, regs);
 
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return;
 	}
-	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) {
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		return; 
+	}
 
 	/* AK: following checks seem to be broken on modern chipsets. FIXME */
 
@@ -792,6 +811,8 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
 		io_check_error(reason, regs);
+
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 /* runs on IST stack. */
@@ -881,7 +902,9 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	info.si_addr = user_mode(regs) ? (void __user *)regs->rip : NULL;
+	MARK(kernel_arch_trap_entry, "%d %ld", 1, instruction_pointer(regs));
 	force_sig_info(SIGTRAP, &info, tsk);
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 
 clear_dr7:
 	set_debugreg(0UL, 7);
@@ -1039,6 +1062,9 @@ asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
 
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
 {
+	MARK(kernel_arch_trap_entry, "%d %ld", 16, instruction_pointer(regs));
+
+	MARK(kernel_arch_trap_exit, MARK_NOARGS);
 }
 
 asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 1e54ddf..9c49413 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -58,6 +58,7 @@ SECTIONS
 				/* Data */
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
 	*(.data)
+	EXTRA_RWDATA
 	CONSTRUCTORS
 	} :data
 
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index a65fc6f..96a3144 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -473,16 +473,21 @@ good_area:
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
+	MARK(kernel_arch_trap_entry, "%d %ld", 14, instruction_pointer(regs));
 	switch (handle_mm_fault(mm, vma, address, write)) {
 	case VM_FAULT_MINOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		tsk->min_flt++;
 		break;
 	case VM_FAULT_MAJOR:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		tsk->maj_flt++;
 		break;
 	case VM_FAULT_SIGBUS:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		goto do_sigbus;
 	default:
+		MARK(kernel_arch_trap_exit, MARK_NOARGS);
 		goto out_of_memory;
 	}
 
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 2e74cb0..02456f5 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -244,6 +244,14 @@ config EMBEDDED_RAMDISK_IMAGE
 	  provide one yourself.
 endmenu
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+source "ltt/Kconfig"
+
+endmenu
+
 source "arch/xtensa/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index a36c104..cd97b14 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -144,7 +144,7 @@ SECTIONS
   _fdata = .;
   .data :
   {
-    *(.data) CONSTRUCTORS
+    *(.data) EXTRA_RWDATA CONSTRUCTORS
     . = ALIGN(XCHAL_ICACHE_LINESIZE);
     *(.data.cacheline_aligned)
   }
diff --git a/block/blktrace.c b/block/blktrace.c
index d3679dd..d36b32e 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -363,10 +363,9 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,
 	if (!bt->dropped_file)
 		goto err;
 
-	bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks);
+	bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks, bt);
 	if (!bt->rchan)
 		goto err;
-	bt->rchan->private_data = bt;
 
 	bt->act_mask = buts.act_mask;
 	if (!bt->act_mask)
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 279c940..daabf90 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -21,7 +21,7 @@
  * With multiple simultaneous hypertransport irq devices it might pay
  * to make this more fine grained.  But start with simple, stupid, and correct.
  */
-static DEFINE_SPINLOCK(ht_irq_lock);
+static IPIPE_DEFINE_SPINLOCK(ht_irq_lock);
 
 struct ht_irq_cfg {
 	struct pci_dev *dev;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 3c4b6c2..f96a049 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -804,6 +804,40 @@ console_initcall(mpc52xx_console_init);
 #endif
 
 
+#ifdef CONFIG_IPIPE
+
+#include <stdarg.h>
+
+void __ipipe_serial_debug(const char *fmt, ...)
+{
+	struct console *co = MPC52xx_PSC_CONSOLE;
+	unsigned long flags, count;
+	struct uart_port *port;
+	char buf[128];
+	va_list ap;
+
+	if (co->index < 0)
+		return;		/* No console. */
+
+	port = &mpc52xx_uart_ports[co->index];
+
+	if (!port->mapbase)
+		return;		/* Too early. */
+
+	va_start(ap, fmt);
+	vsprintf(buf, fmt, ap);
+	va_end(ap);
+	count = strlen(buf);
+
+	local_irq_save_hw(flags);
+	mpc52xx_console_write(co, buf, count);
+	local_irq_restore_hw(flags);
+}
+
+EXPORT_SYMBOL(__ipipe_serial_debug);
+
+#endif
+
 /* ======================================================================== */
 /* UART Driver                                                              */
 /* ======================================================================== */
diff --git a/fs/buffer.c b/fs/buffer.c
index 1ad674f..ff73f4c 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -90,7 +90,9 @@ void fastcall unlock_buffer(struct buffer_head *bh)
  */
 void __wait_on_buffer(struct buffer_head * bh)
 {
+	MARK(fs_buffer_wait_start, "%p", bh);
 	wait_on_bit(&bh->b_state, BH_Lock, sync_buffer, TASK_UNINTERRUPTIBLE);
+	MARK(fs_buffer_wait_end, "%p", bh);
 }
 
 static void
diff --git a/fs/compat.c b/fs/compat.c
index 0ec70e3..6877e80 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -48,6 +48,8 @@
 #include <linux/highmem.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
+#include <linux/ltt-core.h>
+#include <linux/ltt-facilities.h>
 
 #include <net/sock.h>		/* siocdevprivate_ioctl */
 
@@ -1553,6 +1555,18 @@ int compat_do_execve(char * filename,
 
 	retval = search_binary_handler(bprm, regs);
 	if (retval >= 0) {
+#ifdef CONFIG_LTT_USERSPACE_GENERIC
+		{
+			int i;
+			for (i = 0; i < LTT_FAC_PER_PROCESS; i++) {
+				if (current->ltt_facilities[i] == 0)
+					break;
+				WARN_ON(ltt_facility_unregister(
+						current->ltt_facilities[i]));
+			}
+		}
+#endif //CONFIG_LTT_USERSPACE_GENERIC
+		MARK(fs_exec, "%s", filename);
 		free_arg_pages(bprm);
 
 		/* execve success */
diff --git a/fs/exec.c b/fs/exec.c
index 11fe93f..e9c6a9f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,6 +50,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/audit.h>
+#include <linux/ltt-facilities.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1187,6 +1188,18 @@ int do_execve(char * filename,
 
 	retval = search_binary_handler(bprm,regs);
 	if (retval >= 0) {
+#ifdef CONFIG_LTT_USERSPACE_GENERIC
+		{
+			int i;
+			for (i = 0; i < LTT_FAC_PER_PROCESS; i++) {
+				if (current->ltt_facilities[i] == 0)
+					break;
+				WARN_ON(ltt_facility_unregister(
+						current->ltt_facilities[i]));
+			}
+		}
+#endif //CONFIG_LTT_USERSPACE_GENERIC
+		MARK(fs_exec, "%s", filename);
 		free_arg_pages(bprm);
 
 		/* execve success */
diff --git a/fs/ioctl.c b/fs/ioctl.c
index ff61772..d76f730 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -166,6 +166,8 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 	if (!filp)
 		goto out;
 
+	MARK(fs_ioctl, "%u %u %lu", fd, cmd, arg);
+
 	error = security_file_ioctl(filp, cmd, arg);
 	if (error)
 		goto out_fput;
diff --git a/fs/open.c b/fs/open.c
index c989fb4..1629682 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -967,6 +967,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
 				fsnotify_open(f->f_path.dentry);
 				fd_install(fd, f);
 			}
+			MARK(fs_open, "%d %s", fd, tmp);
 		}
 		putname(tmp);
 	}
@@ -1057,6 +1058,7 @@ asmlinkage long sys_close(unsigned int fd)
 	filp = fdt->fd[fd];
 	if (!filp)
 		goto out_unlock;
+	MARK(fs_close, "%u", fd);
 	rcu_assign_pointer(fdt->fd[fd], NULL);
 	FD_CLR(fd, fdt->close_on_exec);
 	__put_unused_fd(files, fd);
diff --git a/fs/read_write.c b/fs/read_write.c
index 707ac21..26cab85 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -15,8 +15,8 @@
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/pagemap.h>
+#include <linux/ltt-tracer.h>	/* for LTT_LOG_RW_SIZE */
 #include "read_write.h"
-
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
@@ -145,6 +145,9 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 		if (res != (loff_t)retval)
 			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
 	}
+
+	MARK(fs_lseek, "%u %8b %u", fd, offset, origin);
+
 	fput_light(file, fput_needed);
 bad:
 	return retval;
@@ -172,6 +175,8 @@ asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
 	offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
 			origin);
 
+	MARK(fs_llseek, "%u %8b %u", fd, offset, origin);
+
 	retval = (int)offset;
 	if (offset >= 0) {
 		retval = -EFAULT;
@@ -362,7 +367,10 @@ asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+		MARK(fs_read, "%u %zu", fd, count);
 		ret = vfs_read(file, buf, count, &pos);
+		MARK(fs_read_data, "%u %zd %k",
+			fd, ret, min(LTT_LOG_RW_SIZE, max(0L, (long)ret)), buf);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
 	}
@@ -380,7 +388,10 @@ asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t co
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+		MARK(fs_write, "%u %zu", fd, count);
 		ret = vfs_write(file, buf, count, &pos);
+		MARK(fs_write_data, "%u %zd %k",
+			fd, ret, min(LTT_LOG_RW_SIZE, max(0L, (long)ret)), buf);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
 	}
@@ -401,8 +412,11 @@ asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = -ESPIPE;
-		if (file->f_mode & FMODE_PREAD)
+		if (file->f_mode & FMODE_PREAD) {
+			MARK(fs_pread64, "%u %zu %8b", fd, count, pos);
 			ret = vfs_read(file, buf, count, &pos);
+		}
+
 		fput_light(file, fput_needed);
 	}
 
@@ -422,8 +436,11 @@ asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = -ESPIPE;
-		if (file->f_mode & FMODE_PWRITE)  
+ 		if (file->f_mode & FMODE_PWRITE) {
+			MARK(fs_pwrite64, "%u %zu %8b",
+				fd, count, pos);
 			ret = vfs_write(file, buf, count, &pos);
+		}
 		fput_light(file, fput_needed);
 	}
 
@@ -669,6 +686,7 @@ sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+		MARK(fs_readv, "%lu %lu", fd, vlen);
 		ret = vfs_readv(file, vec, vlen, &pos);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
@@ -690,6 +708,7 @@ sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+		MARK(fs_writev, "%lu %lu", fd, vlen);
 		ret = vfs_writev(file, vec, vlen, &pos);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
diff --git a/fs/select.c b/fs/select.c
index fe0893a..19584c4 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -239,6 +239,8 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
 				file = fget_light(i, &fput_needed);
 				if (file) {
 					f_op = file->f_op;
+					MARK(fs_select, "%d %8b",
+							i, *timeout);
 					mask = DEFAULT_POLLMASK;
 					if (f_op && f_op->poll)
 						mask = (*f_op->poll)(file, retval ? NULL : wait);
@@ -567,6 +569,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
 		file = fget_light(fd, &fput_needed);
 		mask = POLLNVAL;
 		if (file != NULL) {
+			MARK(fs_pollfd, "%d", fd);
 			mask = DEFAULT_POLLMASK;
 			if (file->f_op && file->f_op->poll)
 				mask = file->f_op->poll(file, pwait);
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index fc77f74..f5cb7b8 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -2,6 +2,7 @@
 #define _ALPHA_ATOMIC_H
 
 #include <asm/barrier.h>
+#include <asm/system.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -175,19 +176,64 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
 	return result;
 }
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
 #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
 
diff --git a/include/asm-alpha/local.h b/include/asm-alpha/local.h
index 90a510f..6ad3ea6 100644
--- a/include/asm-alpha/local.h
+++ b/include/asm-alpha/local.h
@@ -4,37 +4,115 @@
 #include <linux/percpu.h>
 #include <asm/atomic.h>
 
-typedef atomic64_t local_t;
+typedef struct
+{
+	atomic_long_t a;
+} local_t;
 
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
 
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
+static __inline__ long local_add_return(long i, local_t * l)
+{
+	long temp, result;
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%1\n"
+	"	addq %0,%3,%2\n"
+	"	addq %0,%3,%0\n"
+	"	stq_c %0,%1\n"
+	"	beq %0,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
+	:"Ir" (i), "m" (l->a.counter) : "memory");
+	return result;
+}
 
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter++)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
+static __inline__ long local_sub_return(long i, local_t * l)
+{
+	long temp, result;
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%1\n"
+	"	subq %0,%3,%2\n"
+	"	subq %0,%3,%0\n"
+	"	stq_c %0,%1\n"
+	"	beq %0,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
+	:"Ir" (i), "m" (l->a.counter) : "memory");
+	return result;
+}
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	for (;;) {						\
+		if (unlikely(c == (u)))				\
+			break;					\
+		old = local_cmpxchg((l), c, c + (a));	\
+		if (likely(old == c))				\
+			break;					\
+		c = old;					\
+	}							\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
+
+#define local_dec_return(l) local_sub_return(1,(l))
+
+#define local_inc_return(l) local_add_return(1,(l))
+
+#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
+
+#define local_inc_and_test(l) (local_add_return(1, (l)) == 0)
+
+#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
+
+/* Verify if faster than atomic ops */
+#define __local_inc(l)		((l)->a.counter++)
+#define __local_dec(l)		((l)->a.counter++)
+#define __local_add(i,l)	((l)->a.counter+=(i))
+#define __local_sub(i,l)	((l)->a.counter-=(i))
 
 /* Use these for per-cpu local_t variables: on some archs they are
  * much more efficient than these naive implementations.  Note they take
  * a variable, not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
+#define cpu_local_read(l)	local_read(&__get_cpu_var(l))
+#define cpu_local_set(l, i)	local_set(&__get_cpu_var(l), (i))
+
+#define cpu_local_inc(l)	local_inc(&__get_cpu_var(l))
+#define cpu_local_dec(l)	local_dec(&__get_cpu_var(l))
+#define cpu_local_add(i, l)	local_add((i), &__get_cpu_var(l))
+#define cpu_local_sub(i, l)	local_sub((i), &__get_cpu_var(l))
+
+#define __cpu_local_inc(l)	__local_inc(&__get_cpu_var(l))
+#define __cpu_local_dec(l)	__local_dec(&__get_cpu_var(l))
+#define __cpu_local_add(i, l)	__local_add((i), &__get_cpu_var(l))
+#define __cpu_local_sub(i, l)	__local_sub((i), &__get_cpu_var(l))
 
 #endif /* _ALPHA_LOCAL_H */
diff --git a/include/asm-alpha/ltt.h b/include/asm-alpha/ltt.h
new file mode 100644
index 0000000..ed64656
--- /dev/null
+++ b/include/asm-alpha/ltt.h
@@ -0,0 +1,15 @@
+#ifndef _ASM_ALPHA_LTT_H
+#define _ASM_ALPHA_LTT_H
+/*
+ * linux/include/asm-alpha/ltt.h
+ *
+ * Copyright (C) 2005 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * alpha architecture specific definitions for ltt
+ */
+
+#define LTT_HAS_TSC
+
+#endif
diff --git a/include/asm-alpha/marker.h b/include/asm-alpha/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-alpha/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 03e9c0e..42959c3 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -443,6 +443,111 @@ extern void __xchg_called_with_bad_pointer(void);
      (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
   })
 
+static inline unsigned long
+__xchg_u8_local(volatile char *m, unsigned long val)
+{
+	unsigned long ret, tmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%4,7,%3\n"
+	"	insbl	%1,%4,%1\n"
+	"1:	ldq_l	%2,0(%3)\n"
+	"	extbl	%2,%4,%0\n"
+	"	mskbl	%2,%4,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%3)\n"
+	"	beq	%2,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	: "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+	: "r" ((long)m), "1" (val) : "memory");
+
+	return ret;
+}
+
+static inline unsigned long
+__xchg_u16_local(volatile short *m, unsigned long val)
+{
+	unsigned long ret, tmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%4,7,%3\n"
+	"	inswl	%1,%4,%1\n"
+	"1:	ldq_l	%2,0(%3)\n"
+	"	extwl	%2,%4,%0\n"
+	"	mskwl	%2,%4,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%3)\n"
+	"	beq	%2,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	: "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+	: "r" ((long)m), "1" (val) : "memory");
+
+	return ret;
+}
+
+static inline unsigned long
+__xchg_u32_local(volatile int *m, unsigned long val)
+{
+	unsigned long dummy;
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%4\n"
+	"	bis $31,%3,%1\n"
+	"	stl_c %1,%2\n"
+	"	beq %1,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	: "=&r" (val), "=&r" (dummy), "=m" (*m)
+	: "rI" (val), "m" (*m) : "memory");
+
+	return val;
+}
+
+static inline unsigned long
+__xchg_u64_local(volatile long *m, unsigned long val)
+{
+	unsigned long dummy;
+
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%4\n"
+	"	bis $31,%3,%1\n"
+	"	stq_c %1,%2\n"
+	"	beq %1,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	: "=&r" (val), "=&r" (dummy), "=m" (*m)
+	: "rI" (val), "m" (*m) : "memory");
+
+	return val;
+}
+
+#define __xchg_local(ptr, x, size) \
+({ \
+	unsigned long __xchg__res; \
+	volatile void *__xchg__ptr = (ptr); \
+	switch (size) { \
+		case 1: __xchg__res = __xchg_u8_local(__xchg__ptr, x); break; \
+		case 2: __xchg__res = __xchg_u16_local(__xchg__ptr, x); break; \
+		case 4: __xchg__res = __xchg_u32_local(__xchg__ptr, x); break; \
+		case 8: __xchg__res = __xchg_u64_local(__xchg__ptr, x); break; \
+		default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
+	} \
+	__xchg__res; \
+})
+
+#define xchg_local(ptr,x)						     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,	     \
+     		sizeof(*(ptr))); \
+  })
+
 #define tas(ptr) (xchg((ptr),1))
 
 
@@ -596,6 +701,128 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+static inline unsigned long
+__cmpxchg_u8_local(volatile char *m, long old, long new)
+{
+	unsigned long prev, tmp, cmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%5,7,%4\n"
+	"	insbl	%1,%5,%1\n"
+	"1:	ldq_l	%2,0(%4)\n"
+	"	extbl	%2,%5,%0\n"
+	"	cmpeq	%0,%6,%3\n"
+	"	beq	%3,2f\n"
+	"	mskbl	%2,%5,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%4)\n"
+	"	beq	%2,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br	1b\n"
+	".previous"
+	: "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+	: "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+	return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u16_local(volatile short *m, long old, long new)
+{
+	unsigned long prev, tmp, cmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%5,7,%4\n"
+	"	inswl	%1,%5,%1\n"
+	"1:	ldq_l	%2,0(%4)\n"
+	"	extwl	%2,%5,%0\n"
+	"	cmpeq	%0,%6,%3\n"
+	"	beq	%3,2f\n"
+	"	mskwl	%2,%5,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%4)\n"
+	"	beq	%2,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br	1b\n"
+	".previous"
+	: "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+	: "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+	return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u32_local(volatile int *m, int old, int new)
+{
+	unsigned long prev, cmp;
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%5\n"
+	"	cmpeq %0,%3,%1\n"
+	"	beq %1,2f\n"
+	"	mov %4,%1\n"
+	"	stl_c %1,%2\n"
+	"	beq %1,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br 1b\n"
+	".previous"
+	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
+	: "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+	return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u64_local(volatile long *m, unsigned long old, unsigned long new)
+{
+	unsigned long prev, cmp;
+
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%5\n"
+	"	cmpeq %0,%3,%1\n"
+	"	beq %1,2f\n"
+	"	mov %4,%1\n"
+	"	stq_c %1,%2\n"
+	"	beq %1,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br 1b\n"
+	".previous"
+	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
+	: "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+	return prev;
+}
+
+static __always_inline unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+		int size)
+{
+	switch (size) {
+		case 1:
+			return __cmpxchg_u8_local(ptr, old, new);
+		case 2:
+			return __cmpxchg_u16_local(ptr, old, new);
+		case 4:
+			return __cmpxchg_u32_local(ptr, old, new);
+		case 8:
+			return __cmpxchg_u64_local(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg_local(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 #endif /* __ASSEMBLY__ */
 
 #define arch_align_stack(x) (x)
diff --git a/include/asm-alpha/thread_info.h b/include/asm-alpha/thread_info.h
index 69ffd93..3e3fbe1 100644
--- a/include/asm-alpha/thread_info.h
+++ b/include/asm-alpha/thread_info.h
@@ -76,12 +76,14 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define TIF_UAC_NOFIX		7
 #define TIF_UAC_SIGBUS		8
 #define TIF_MEMDIE		9
+#define TIF_SYSCALL_AUDIT	10
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 
 /* Work to do on interrupt/exception return.  */
 #define _TIF_WORK_MASK		(_TIF_NOTIFY_RESUME	\
diff --git a/include/asm-arm/ltt.h b/include/asm-arm/ltt.h
new file mode 100644
index 0000000..88f3b84
--- /dev/null
+++ b/include/asm-arm/ltt.h
@@ -0,0 +1,82 @@
+/*
+ * linux/include/asm-arm/ltt.h
+ *
+ * Copyright (C) 2005, Mathieu Desnoyers
+ *
+ * ARM definitions for tracing system
+ */
+
+#ifndef _ASM_ARM_LTT_H
+#define _ASM_ARM_LTT_H
+
+#include <linux/jiffies.h>
+#include <linux/seqlock.h>
+
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_ARM
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+#undef LTT_HAS_TSC
+
+#define LTTNG_LOGICAL_SHIFT 13
+
+extern atomic_t lttng_logical_clock;
+
+static inline u32 ltt_get_timestamp32(void)
+{
+	unsigned long seq;
+	unsigned long try = 5;
+	u32 ret;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		ret = (jiffies << LTTNG_LOGICAL_SHIFT) 
+			| (atomic_add_return(1, &lttng_logical_clock));
+	} while (read_seqretry(&xtime_lock, seq) && (--try) > 0);
+
+	if (try == 0)
+		return 0;
+	else
+		return ret;
+}
+
+
+/* The shift overflow doesn't matter */
+static inline u64 ltt_get_timestamp64(void)
+{
+	unsigned long seq;
+	unsigned long try = 5;
+	u64 ret;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		ret = (jiffies_64 << LTTNG_LOGICAL_SHIFT) 
+			| (atomic_add_return(1, &lttng_logical_clock));
+	} while (read_seqretry(&xtime_lock, seq) && (--try) > 0);
+
+	if (try == 0)
+		return 0;
+	else
+		return ret;
+}
+
+/* this has to be called with the write seqlock held */
+static inline void ltt_reset_timestamp(void)
+{
+	atomic_set(&lttng_logical_clock, 0);
+}
+
+
+static inline unsigned int ltt_frequency(void)
+{
+  return HZ << LTTNG_LOGICAL_SHIFT;
+}
+
+
+static inline u32 ltt_freq_scale(void)
+{
+  return 1;
+}
+
+
+
+#endif
diff --git a/include/asm-arm/marker.h b/include/asm-arm/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-arm/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
index 5014794..e611e18 100644
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -139,10 +139,12 @@ extern void iwmmxt_task_switch(struct thread_info *);
  *  TIF_NEED_RESCHED	- rescheduling necessary
  *  TIF_USEDFPU		- FPU was used by this task this quantum (SMP)
  *  TIF_POLLING_NRFLAG	- true if poll_idle() is polling TIF_NEED_RESCHED
+ *  TIF_SYSCALL_TRACE	- Syscall audting active - LTTng
  */
 #define TIF_NOTIFY_RESUME	0
 #define TIF_SIGPENDING		1
 #define TIF_NEED_RESCHED	2
+#define	TIF_SYSCALL_AUDIT	7
 #define TIF_SYSCALL_TRACE	8
 #define TIF_POLLING_NRFLAG	16
 #define TIF_USING_IWMMXT	17
@@ -153,6 +155,7 @@ extern void iwmmxt_task_switch(struct thread_info *);
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+#define	_TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
 #define _TIF_FREEZE		(1 << TIF_FREEZE)
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index 97e7060..14589f5 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -372,6 +372,8 @@
 #define __NR_move_pages			(__NR_SYSCALL_BASE+344)
 #define __NR_getcpu			(__NR_SYSCALL_BASE+345)
 					/* 346 for epoll_pwait */
+#define	__NR_ltt_trace_generic		(__NR_SYSCALL_BASE+347)
+#define	__NR_ltt_register_generic	(__NR_SYSCALL_BASE+348)
 
 /*
  * The following SWIs are ARM private.
diff --git a/include/asm-arm26/ltt.h b/include/asm-arm26/ltt.h
new file mode 100644
index 0000000..a230745
--- /dev/null
+++ b/include/asm-arm26/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_ARM26_LTT_H
+#define _ASM_ARM26_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-arm26/marker.h b/include/asm-arm26/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-arm26/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-avr32/atomic.h b/include/asm-avr32/atomic.h
index c40b603..b9c2548 100644
--- a/include/asm-avr32/atomic.h
+++ b/include/asm-avr32/atomic.h
@@ -173,7 +173,7 @@ static inline int atomic_sub_if_positive(int i, atomic_t *v)
 }
 
 #define atomic_xchg(v, new)	(xchg(&((v)->counter), new))
-#define atomic_cmpxchg(v, o, n)	((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n)	(cmpxchg(&((v)->counter), (o), (n)))
 
 #define atomic_sub(i, v)	(void)atomic_sub_return(i, v)
 #define atomic_add(i, v)	(void)atomic_add_return(i, v)
diff --git a/include/asm-cris/ltt.h b/include/asm-cris/ltt.h
new file mode 100644
index 0000000..da55289
--- /dev/null
+++ b/include/asm-cris/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_CRIS_LTT_H
+#define _ASM_CRIS_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-cris/marker.h b/include/asm-cris/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-cris/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-frv/ltt.h b/include/asm-frv/ltt.h
new file mode 100644
index 0000000..14c97dd
--- /dev/null
+++ b/include/asm-frv/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_FRV_LTT_H
+#define _ASM_FRV_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-frv/marker.h b/include/asm-frv/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-frv/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
index 1166899..be303b3 100644
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -13,7 +13,6 @@
 #define _ASM_SYSTEM_H
 
 #include <linux/linkage.h>
-#include <asm/atomic.h>
 
 struct thread_struct;
 
@@ -197,4 +196,73 @@ extern void free_initmem(void);
 
 #define arch_align_stack(x) (x)
 
+/*****************************************************************************/
+/*
+ * compare and conditionally exchange value with memory
+ * - if (*ptr == test) then orig = *ptr; *ptr = test;
+ * - if (*ptr != test) then orig = *ptr;
+ */
+#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
+
+#define cmpxchg(ptr, test, new)							\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig, __xg_tmp;					\
+	__typeof__(*(ptr)) __xg_test = (test);					\
+	__typeof__(*(ptr)) __xg_new = (new);					\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4:									\
+		asm volatile(							\
+			"0:						\n"	\
+			"	orcc		gr0,gr0,gr0,icc3	\n"	\
+			"	ckeq		icc3,cc7		\n"	\
+			"	ld.p		%M0,%1			\n"	\
+			"	orcr		cc7,cc7,cc3		\n"	\
+			"	sub%I4cc	%1,%4,%2,icc0		\n"	\
+			"	bne		icc0,#0,1f		\n"	\
+			"	cst.p		%3,%M0		,cc3,#1	\n"	\
+			"	corcc		gr29,gr29,gr0	,cc3,#1	\n"	\
+			"	beq		icc3,#0,0b		\n"	\
+			"1:						\n"	\
+			: "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)	\
+			: "r"(__xg_new), "NPr"(__xg_test)			\
+			: "memory", "cc7", "cc3", "icc3", "icc0"		\
+			);							\
+		break;								\
+										\
+	default:								\
+		__xg_orig = 0;							\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#else
+
+extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
+
+#define cmpxchg(ptr, test, new)							\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig;						\
+	__typeof__(*(ptr)) __xg_test = (test);					\
+	__typeof__(*(ptr)) __xg_new = (new);					\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break;	\
+	default:								\
+		__xg_orig = 0;							\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#endif
+
+
 #endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index b7e4a04..8cc36d8 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -66,6 +66,76 @@ static inline void atomic_long_sub(long i, atomic_long_t *l)
 	atomic64_sub(i, v);
 }
 
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return atomic64_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return atomic64_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return atomic64_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return atomic64_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return (long)atomic64_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return (long)atomic64_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return (long)atomic64_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return (long)atomic64_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+	atomic64_t *v = (atomic64_t *)l;
+	
+	return (long)atomic64_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+	(atomic_cmpxchg((atomic64_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+	(atomic_xchg((atomic64_t *)(l), (new)))
+
 #else  /*  BITS_PER_LONG == 64  */
 
 typedef atomic_t atomic_long_t;
@@ -113,6 +183,76 @@ static inline void atomic_long_sub(long i, atomic_long_t *l)
 	atomic_sub(i, v);
 }
 
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return atomic_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return atomic_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return atomic_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return atomic_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return (long)atomic_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return (long)atomic_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return (long)atomic_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return (long)atomic_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+	atomic_t *v = (atomic_t *)l;
+	
+	return (long)atomic_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+	(atomic_cmpxchg((atomic_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+	(atomic_xchg((atomic_t *)(l), (new)))
+
 #endif  /*  BITS_PER_LONG == 64  */
 
 #endif  /*  _ASM_GENERIC_ATOMIC_H  */
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h
index ab46929..33d7d04 100644
--- a/include/asm-generic/local.h
+++ b/include/asm-generic/local.h
@@ -33,6 +33,19 @@ typedef struct
 #define local_add(i,l)	atomic_long_add((i),(&(l)->a))
 #define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
 
+#define local_sub_and_test(i, l) atomic_long_sub_and_test((i), (&(l)->a))
+#define local_dec_and_test(l) atomic_long_dec_and_test(&(l)->a)
+#define local_inc_and_test(l) atomic_long_inc_and_test(&(l)->a)
+#define local_add_negative(i, l) atomic_long_add_negative((i), (&(l)->a))
+#define local_add_return(i, l) atomic_long_add_return((i), (&(l)->a))
+#define local_sub_return(i, l) atomic_long_sub_return((i), (&(l)->a))
+#define local_inc_return(l) atomic_long_inc_return(&(l)->a)
+
+#define local_cmpxchg(l, o, n) atomic_long_cmpxchg((&(l)->a), (o), (n))
+#define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n))
+#define local_add_unless(l, a, u) atomic_long_add_unless((&(l)->a), (a), (u))
+#define local_inc_not_zero(l) atomic_long_inc_not_zero(&(l)->a)
+
 /* Non-atomic variants, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well. */
 #define __local_inc(l)		local_set((l), local_read(l) + 1)
@@ -44,19 +57,19 @@ typedef struct
  * much more efficient than these naive implementations.  Note they take
  * a variable (eg. mystruct.foo), not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
+#define cpu_local_read(l)	local_read(&__get_cpu_var(l))
+#define cpu_local_set(l, i)	local_set(&__get_cpu_var(l), (i))
+#define cpu_local_inc(l)	local_inc(&__get_cpu_var(l))
+#define cpu_local_dec(l)	local_dec(&__get_cpu_var(l))
+#define cpu_local_add(i, l)	local_add((i), &__get_cpu_var(l))
+#define cpu_local_sub(i, l)	local_sub((i), &__get_cpu_var(l))
 
 /* Non-atomic increments, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well.
  */
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
+#define __cpu_local_inc(l)	__local_inc(&__get_cpu_var(l))
+#define __cpu_local_dec(l)	__local_dec(&__get_cpu_var(l))
+#define __cpu_local_add(i, l)	__local_add((i), &__get_cpu_var(l))
+#define __cpu_local_sub(i, l)	__local_sub((i), &__get_cpu_var(l))
 
 #endif /* _ASM_GENERIC_LOCAL_H */
diff --git a/include/asm-generic/ltt.h b/include/asm-generic/ltt.h
new file mode 100644
index 0000000..cd2760e
--- /dev/null
+++ b/include/asm-generic/ltt.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_GENERIC_LTT_H
+#define _ASM_GENERIC_LTT_H
+/*
+ * linux/include/asm-generic/ltt.h
+ *
+ * Copyright (C) 2005 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Architecture dependent definitions for ltt
+ * Architecture without TSC
+ */
+
+#endif
diff --git a/include/asm-generic/marker.h b/include/asm-generic/marker.h
new file mode 100644
index 0000000..012db0a
--- /dev/null
+++ b/include/asm-generic/marker.h
@@ -0,0 +1,37 @@
+#ifndef _ASM_GENERIC_MARKER_H
+#define _ASM_GENERIC_MARKER_H
+
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Generic header.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ *
+ * Note : the empty asm volatile with read constraint is used here instead of a
+ * "used" attribute to fix a gcc 4.1.x bug.
+ */
+
+/* Default flags, used by MARK() */
+#define _MF_DEFAULT			(_MF_LOCKDEP | _MF_PRINTK)
+
+/* Fallback on the generic markers, since no optimized version is available */
+#define MARK_OPTIMIZED			MARK_GENERIC
+#define _MARK				MARK_GENERIC
+
+/* Marker with default behavior */
+#define MARK(format, args...)		_MARK(_MF_DEFAULT, format, ## args)
+
+/* Architecture dependant marker information, used internally for marker
+ * activation. */
+
+#define MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET \
+		MARK_GENERIC_ENABLE_IMMEDIATE_OFFSET
+#define MARK_OPTIMIZED_ENABLE_TYPE	MARK_GENERIC_ENABLE_TYPE
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define MARK_OPTIMIZED_ENABLE		MARK_GENERIC_ENABLE
+
+#define marker_optimized_set_enable marker_generic_set_enable
+
+#endif /* _ASM_GENERIC_MARKER_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 9fcc8d9..4ddc8a1 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -116,11 +116,22 @@
 		*(__kcrctab_gpl_future)					\
 		VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;	\
 	}								\
-									\
+	/* Kernel markers : pointers */					\
+	__markers : AT(ADDR(__markers) - LOAD_OFFSET) {			\
+		VMLINUX_SYMBOL(__start___markers) = .;			\
+		*(__markers)						\
+		VMLINUX_SYMBOL(__stop___markers) = .;			\
+	}								\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\
 	}								\
+	/* Kernel markers : strings */					\
+	__markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) {	\
+		*(__markers_strings)					\
+	}								\
+	__end_rodata = .;						\
+	. = ALIGN(4096);						\
 									\
 	/* Built-in module parameters. */				\
 	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
@@ -132,6 +143,10 @@
 									\
 	. = ALIGN(4096);
 
+#define EXTRA_RWDATA							\
+	. = ALIGN(8);							\
+	*(__markers_data)						\
+
 #define SECURITY_INIT							\
 	.security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
 		VMLINUX_SYMBOL(__security_initcall_start) = .;		\
@@ -228,4 +243,3 @@
   	*(.initcall6s.init)						\
   	*(.initcall7.init)						\
   	*(.initcall7s.init)
-
diff --git a/include/asm-h8300/ltt.h b/include/asm-h8300/ltt.h
new file mode 100644
index 0000000..c7d3c31
--- /dev/null
+++ b/include/asm-h8300/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_H8300_LTT_H
+#define _ASM_H8300_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-h8300/marker.h b/include/asm-h8300/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-h8300/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h
index c57441b..17e4376 100644
--- a/include/asm-i386/atomic.h
+++ b/include/asm-i386/atomic.h
@@ -207,8 +207,8 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v)
 	return atomic_add_return(-i,v);
 }
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
 
 /**
  * atomic_add_unless - add unless the number is a given value
@@ -219,20 +219,21 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_inc_return(v)  (atomic_add_return(1,v))
diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h
index 12060e2..da203fa 100644
--- a/include/asm-i386/local.h
+++ b/include/asm-i386/local.h
@@ -2,47 +2,198 @@
 #define _ARCH_I386_LOCAL_H
 
 #include <linux/percpu.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
 
 typedef struct
 {
-	volatile long counter;
+	atomic_long_t a;
 } local_t;
 
-#define LOCAL_INIT(i)	{ (i) }
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define local_read(v)	((v)->counter)
-#define local_set(v,i)	(((v)->counter) = (i))
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
 
-static __inline__ void local_inc(local_t *v)
+static __inline__ void local_inc(local_t *l)
 {
 	__asm__ __volatile__(
 		"incl %0"
-		:"+m" (v->counter));
+		:"+m" (l->a.counter));
 }
 
-static __inline__ void local_dec(local_t *v)
+static __inline__ void local_dec(local_t *l)
 {
 	__asm__ __volatile__(
 		"decl %0"
-		:"+m" (v->counter));
+		:"+m" (l->a.counter));
 }
 
-static __inline__ void local_add(long i, local_t *v)
+static __inline__ void local_add(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"addl %1,%0"
-		:"+m" (v->counter)
+		:"+m" (l->a.counter)
 		:"ir" (i));
 }
 
-static __inline__ void local_sub(long i, local_t *v)
+static __inline__ void local_sub(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"subl %1,%0"
-		:"+m" (v->counter)
+		:"+m" (l->a.counter)
 		:"ir" (i));
 }
 
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ * 
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_sub_and_test(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"subl %2,%0; sete %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		:"ir" (i) : "memory");
+	return c;
+}
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer of type local_t
+ * 
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */ 
+static __inline__ int local_dec_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"decl %0; sete %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		: : "memory");
+	return c != 0;
+}
+
+/**
+ * local_inc_and_test - increment and test 
+ * @l: pointer of type local_t
+ * 
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */ 
+static __inline__ int local_inc_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"incl %0; sete %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		: : "memory");
+	return c != 0;
+}
+
+/**
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ * 
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */ 
+static __inline__ int local_add_negative(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"addl %2,%0; sets %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		:"ir" (i) : "memory");
+	return c;
+}
+
+/**
+ * local_add_return - add and return
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns @i + @l
+ */
+static __inline__ long local_add_return(long i, local_t *l)
+{
+	long __i;
+#ifdef CONFIG_M386
+	unsigned long flags;
+	if(unlikely(boot_cpu_data.x86==3))
+		goto no_xadd;
+#endif
+	/* Modern 486+ processor */
+	__i = i;
+	__asm__ __volatile__(
+		"xaddl %0, %1;"
+		:"+r" (i), "+m" (l->a.counter)
+		: : "memory");
+	return i + __i;
+
+#ifdef CONFIG_M386
+no_xadd: /* Legacy 386 processor */
+	local_irq_save(flags);
+	__i = local_read(l);
+	local_set(l, i + __i);
+	local_irq_restore(flags);
+	return i + __i;
+#endif
+}
+
+static __inline__ long local_sub_return(long i, local_t *l)
+{
+	return local_add_return(-i,l);
+}
+
+#define local_inc_return(l)  (local_add_return(1,l))
+#define local_dec_return(l)  (local_sub_return(1,l))
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+/* Always has a lock prefix */
+#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	for (;;) {						\
+		if (unlikely(c == (u)))				\
+			break;					\
+		old = local_cmpxchg((l), c, c + (a));	\
+		if (likely(old == c))				\
+			break;					\
+		c = old;					\
+	}							\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
 /* On x86, these are no better than the atomic variants. */
 #define __local_inc(l)		local_inc(l)
 #define __local_dec(l)		local_dec(l)
@@ -56,27 +207,27 @@ static __inline__ void local_sub(long i, local_t *v)
 
 /* Need to disable preemption for the cpu local counters otherwise we could
    still access a variable of a previous CPU in a non atomic way. */
-#define cpu_local_wrap_v(v)	 	\
+#define cpu_local_wrap_v(l)	 	\
 	({ local_t res__;		\
 	   preempt_disable(); 		\
-	   res__ = (v);			\
+	   res__ = (l);			\
 	   preempt_enable();		\
 	   res__; })
-#define cpu_local_wrap(v)		\
+#define cpu_local_wrap(l)		\
 	({ preempt_disable();		\
-	   v;				\
+	   l;				\
 	   preempt_enable(); })		\
 
-#define cpu_local_read(v)    cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
-#define cpu_local_set(v, i)  cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
-#define cpu_local_inc(v)     cpu_local_wrap(local_inc(&__get_cpu_var(v)))
-#define cpu_local_dec(v)     cpu_local_wrap(local_dec(&__get_cpu_var(v)))
-#define cpu_local_add(i, v)  cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
-#define cpu_local_sub(i, v)  cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
-
-#define __cpu_local_inc(v)	cpu_local_inc(v)
-#define __cpu_local_dec(v)	cpu_local_dec(v)
-#define __cpu_local_add(i, v)	cpu_local_add((i), (v))
-#define __cpu_local_sub(i, v)	cpu_local_sub((i), (v))
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
 #endif /* _ARCH_I386_LOCAL_H */
diff --git a/include/asm-i386/ltt.h b/include/asm-i386/ltt.h
new file mode 100644
index 0000000..63d0ec2
--- /dev/null
+++ b/include/asm-i386/ltt.h
@@ -0,0 +1,98 @@
+#ifndef _ASM_I386_LTT_H
+#define _ASM_I386_LTT_H
+/*
+ * linux/include/asm-i386/ltt.h
+ *
+ * Copyright (C) 2005,2006 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * i386 time and TSC definitions for ltt
+ */
+
+#include <asm/timex.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_I386
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+/* Minimum duration of a probe, in cycles */
+#define LTT_MIN_PROBE_DURATION 200
+
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+u64 ltt_heartbeat_read_synthetic_tsc(void);
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+
+#ifdef CONFIG_LTT_TEST_TSC
+extern cycles_t ltt_last_tsc;
+extern int ltt_tsc_is_sync;
+
+/* Support for architectures with non-sync TSCs.
+ * When the local TSC is discovered to lag behind the highest TSC counter, we
+ * increment the TSC count of an amount that should be, ideally, lower than the
+ * execution time of this routine, in cycles : this is the granularity we look
+ * for : we must be able to order the events. */
+static inline cycles_t ltt_async_tsc_read(void)
+{
+	cycles_t new_tsc;
+	cycles_t last_tsc;
+
+	new_tsc = get_cycles();
+	do {
+		last_tsc = ltt_last_tsc;
+		if (new_tsc < last_tsc)
+			new_tsc = last_tsc + LTT_MIN_PROBE_DURATION;
+		/* If cmpxchg fails with a value higher than the new_tsc, don't
+		 * retry : the value has been incremented and the events
+		 * happened almost at the same time.
+		 * We must retry if cmpxchg fails with a lower value :
+		 * it means that we are the CPU with highest frequency and
+		 * therefore MUST update the value.
+		 */
+	} while (cmpxchg(&ltt_last_tsc, last_tsc, new_tsc) < new_tsc);
+	return new_tsc;
+}
+
+static inline u32 ltt_get_timestamp32(void)
+{
+	if (ltt_tsc_is_sync)
+		return (u32)get_cycles(); /* only need the 32 LSB */
+	else
+		return (u32)ltt_async_tsc_read();
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	if (ltt_tsc_is_sync)
+		return get_cycles();
+	else
+		return ltt_async_tsc_read();
+}
+#else //CONFIG_LTT_TEST_TSC
+static inline u32 ltt_get_timestamp32(void)
+{
+	return (u32)get_cycles(); /* only need the 32 LSB */
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	return get_cycles();
+}
+#endif //CONFIG_LTT_TEST_TSC
+
+static inline void ltt_reset_timestamp(void)
+{
+	/* FIXME : eventually do a periodic IPI to have an upper bound on
+	 * the TSC inaccuracy */
+}
+
+static inline unsigned int ltt_frequency(void)
+{
+	return cpu_khz;
+}
+
+static inline u32 ltt_freq_scale(void)
+{
+	return 1000;
+}
+
+#endif //_ASM_I386_LTT_H
diff --git a/include/asm-i386/marker.h b/include/asm-i386/marker.h
new file mode 100644
index 0000000..cd0963b
--- /dev/null
+++ b/include/asm-i386/marker.h
@@ -0,0 +1,79 @@
+#ifndef _ASM_I386_MARKER_H
+#define _ASM_I386_MARKER_H
+
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. i386 architecture optimisations.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+
+#ifdef CONFIG_MARKERS
+
+#define _MF_DEFAULT (_MF_OPTIMIZED | _MF_LOCKDEP | _MF_PRINTK)
+
+/* Optimized version of the markers */
+#define MARK_OPTIMIZED(flags, name, format, args...) \
+	do { \
+		static const char __mstrtab_name_##name[] \
+		__attribute__((section("__markers_strings"))) \
+		= #name; \
+		static const char __mstrtab_format_##name[] \
+		__attribute__((section("__markers_strings"))) \
+		= format; \
+		static struct __mark_marker_data __mark_data_##name \
+		__attribute__((section("__markers_data"))) = \
+		{ __mstrtab_name_##name,  __mstrtab_format_##name, \
+		(flags) | _MF_OPTIMIZED, __mark_empty_function, NULL }; \
+		char condition; \
+		asm volatile(	".section __markers, \"a\", @progbits;\n\t" \
+					".long %1, 0f;\n\t" \
+					".previous;\n\t" \
+					".align 2\n\t" \
+					"0:\n\t" \
+					"movb $0,%0;\n\t" \
+				: "=r" (condition) \
+				: "m" (__mark_data_##name)); \
+		__mark_check_format(format, ## args); \
+		if (unlikely(condition)) { \
+			preempt_disable(); \
+			(*__mark_data_##name.call)(&__mark_data_##name, \
+						format, ## args); \
+			preempt_enable(); \
+		} \
+	} while (0)
+
+/* Marker macro selecting the generic or optimized version of marker, depending
+ * on the flags specified. */
+#define _MARK(flags, format, args...) \
+do { \
+	if (((flags) & _MF_LOCKDEP) && ((flags) & _MF_OPTIMIZED)) \
+		MARK_OPTIMIZED(flags, format, ## args); \
+	else \
+		MARK_GENERIC(flags, format, ## args); \
+} while (0)
+
+/* Marker with default behavior */
+#define MARK(format, args...) _MARK(_MF_DEFAULT, format, ## args)
+
+/* Architecture dependant marker information, used internally for marker
+ * activation. */
+
+/* Offset of the immediate value from the start of the movb instruction, in
+ * bytes. */
+#define MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET 1
+#define MARK_OPTIMIZED_ENABLE_TYPE char
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define MARK_OPTIMIZED_ENABLE(a) \
+	*(MARK_OPTIMIZED_ENABLE_TYPE*) \
+		((char*)a+MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET)
+
+extern int marker_optimized_set_enable(void *address, char enable);
+
+#endif
+#endif //_ASM_I386_MARKER_H
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index a6d20d9..419fa72 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -274,6 +274,9 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 #define sync_cmpxchg(ptr,o,n)\
 	((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg_local(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
 #endif
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
@@ -336,6 +339,33 @@ static inline unsigned long __sync_cmpxchg(volatile void *ptr,
 	return old;
 }
 
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+			unsigned long old, unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__("cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__("cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__("cmpxchgl %1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
 #ifndef CONFIG_X86_CMPXCHG
 /*
  * Building a kernel capable running on 80386. It may be necessary to
@@ -372,6 +402,17 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
 					(unsigned long)(n), sizeof(*(ptr))); \
 	__ret;								\
 })
+#define cmpxchg_local(ptr,o,n)						\
+({									\
+	__typeof__(*(ptr)) __ret;					\
+	if (likely(boot_cpu_data.x86 > 3))				\
+		__ret = __cmpxchg_local((ptr), (unsigned long)(o),	\
+					(unsigned long)(n), sizeof(*(ptr))); \
+	else								\
+		__ret = cmpxchg_386((ptr), (unsigned long)(o),		\
+					(unsigned long)(n), sizeof(*(ptr))); \
+	__ret;								\
+})
 #endif
 
 #ifdef CONFIG_X86_CMPXCHG64
@@ -390,10 +431,26 @@ static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long l
 	return prev;
 }
 
+static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
+			unsigned long long old, unsigned long long new)
+{
+	unsigned long long prev;
+	__asm__ __volatile__("cmpxchg8b %3"
+			     : "=A"(prev)
+			     : "b"((unsigned long)new),
+			       "c"((unsigned long)(new >> 32)),
+			       "m"(*__xg(ptr)),
+			       "0"(old)
+			     : "memory");
+	return prev;
+}
+
 #define cmpxchg64(ptr,o,n)\
 	((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
 					(unsigned long long)(n)))
-
+#define cmpxchg64_local(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
+					(unsigned long long)(n)))
 #endif
     
 /*
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 833fa17..5dd745c 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -325,10 +325,12 @@
 #define __NR_move_pages		317
 #define __NR_getcpu		318
 #define __NR_epoll_pwait	319
+#define __NR_ltt_trace_generic	320
+#define __NR_ltt_register_generic	321
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 320
+#define NR_syscalls 322
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
index 569ec75..1fc3b83 100644
--- a/include/asm-ia64/atomic.h
+++ b/include/asm-ia64/atomic.h
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 
 #include <asm/intrinsics.h>
+#include <asm/system.h>
 
 /*
  * On IA-64, counter must always be volatile to ensure that that the
@@ -88,25 +89,47 @@ ia64_atomic64_sub (__s64 i, atomic64_t *v)
 	return new;
 }
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+#define atomic64_cmpxchg(v, old, new) \
+	(cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #define atomic_add_return(i,v)						\
 ({									\
 	int __ia64_aar_i = (i);						\
diff --git a/include/asm-ia64/local.h b/include/asm-ia64/local.h
index dc51909..c11c530 100644
--- a/include/asm-ia64/local.h
+++ b/include/asm-ia64/local.h
@@ -1,50 +1 @@
-#ifndef _ASM_IA64_LOCAL_H
-#define _ASM_IA64_LOCAL_H
-
-/*
- * Copyright (C) 2003 Hewlett-Packard Co
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/percpu.h>
-
-typedef struct {
-	atomic64_t val;
-} local_t;
-
-#define LOCAL_INIT(i)	((local_t) { { (i) } })
-#define local_read(l)	atomic64_read(&(l)->val)
-#define local_set(l, i)	atomic64_set(&(l)->val, i)
-#define local_inc(l)	atomic64_inc(&(l)->val)
-#define local_dec(l)	atomic64_dec(&(l)->val)
-#define local_add(i, l)	atomic64_add((i), &(l)->val)
-#define local_sub(i, l)	atomic64_sub((i), &(l)->val)
-
-/* Non-atomic variants, i.e., preemption disabled and won't be touched in interrupt, etc.  */
-
-#define __local_inc(l)		(++(l)->val.counter)
-#define __local_dec(l)		(--(l)->val.counter)
-#define __local_add(i,l)	((l)->val.counter += (i))
-#define __local_sub(i,l)	((l)->val.counter -= (i))
-
-/*
- * Use these for per-cpu local_t variables.  Note they take a variable (eg. mystruct.foo),
- * not an address.
- */
-#define cpu_local_read(v)	local_read(&__ia64_per_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__ia64_per_cpu_var(v), (i))
-#define cpu_local_inc(v)	local_inc(&__ia64_per_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__ia64_per_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__ia64_per_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__ia64_per_cpu_var(v))
-
-/*
- * Non-atomic increments, i.e., preemption disabled and won't be touched in interrupt,
- * etc.
- */
-#define __cpu_local_inc(v)	__local_inc(&__ia64_per_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__ia64_per_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__ia64_per_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__ia64_per_cpu_var(v))
-
-#endif /* _ASM_IA64_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-ia64/ltt.h b/include/asm-ia64/ltt.h
new file mode 100644
index 0000000..02ab950
--- /dev/null
+++ b/include/asm-ia64/ltt.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_IA64_LTT_H
+#define _ASM_IA64_LTT_H
+
+#define LTT_HAS_TSC
+
+#endif
diff --git a/include/asm-ia64/marker.h b/include/asm-ia64/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-ia64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-m32r/ltt.h b/include/asm-m32r/ltt.h
new file mode 100644
index 0000000..7b0a3fe
--- /dev/null
+++ b/include/asm-m32r/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_M32R_LTT_H
+#define _ASM_M32R_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-m32r/marker.h b/include/asm-m32r/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-m32r/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-m68k/ltt.h b/include/asm-m68k/ltt.h
new file mode 100644
index 0000000..1c12e33
--- /dev/null
+++ b/include/asm-m68k/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_M68K_LTT_H
+#define _ASM_M68K_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-m68k/marker.h b/include/asm-m68k/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-m68k/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
index c4d622a..a320466 100644
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -55,6 +55,7 @@ struct thread_info {
  */
 #define TIF_SIGPENDING		6	/* signal pending */
 #define TIF_NEED_RESCHED	7	/* rescheduling necessary */
+#define TIF_SYSCALL_AUDIT	13	/* syscall audit active */
 #define TIF_DELAYED_TRACE	14	/* single step a syscall */
 #define TIF_SYSCALL_TRACE	15	/* syscall trace active */
 #define TIF_MEMDIE		16
diff --git a/include/asm-m68knommu/ltt.h b/include/asm-m68knommu/ltt.h
new file mode 100644
index 0000000..f139760
--- /dev/null
+++ b/include/asm-m68knommu/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_M68KNOMMU_LTT_H
+#define _ASM_M68KNOMMU_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-m68knommu/marker.h b/include/asm-m68knommu/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-m68knommu/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-m68knommu/thread_info.h b/include/asm-m68knommu/thread_info.h
index b8f009e..a57a7a3 100644
--- a/include/asm-m68knommu/thread_info.h
+++ b/include/asm-m68knommu/thread_info.h
@@ -89,6 +89,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_POLLING_NRFLAG	4	/* true if poll_idle() is polling
 					   TIF_NEED_RESCHED */
 #define TIF_MEMDIE		5
+#define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
@@ -96,6 +97,8 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+#define _TIF_MEMDIE		(1<<TIF_MEMDIE)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 
 #define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
 
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index c1a2409..fa9f742 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -18,6 +18,7 @@
 #include <asm/barrier.h>
 #include <asm/cpu-features.h>
 #include <asm/war.h>
+#include <asm/system.h>
 
 typedef struct { volatile int counter; } atomic_t;
 
@@ -291,8 +292,8 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 	return result;
 }
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
 
 /**
  * atomic_add_unless - add unless the number is a given value
@@ -303,14 +304,20 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
@@ -651,6 +658,36 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
 	return result;
 }
 
+#define atomic64_cmpxchg(v, o, n) \
+	(((__typeof__((v)->counter)))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
 #define atomic64_inc_return(v) atomic64_add_return(1,(v))
 
diff --git a/include/asm-mips/local.h b/include/asm-mips/local.h
index 9e2d43b..ed882c8 100644
--- a/include/asm-mips/local.h
+++ b/include/asm-mips/local.h
@@ -1,60 +1,288 @@
-#ifndef _ASM_LOCAL_H
-#define _ASM_LOCAL_H
+#ifndef _ARCH_MIPS_LOCAL_H
+#define _ARCH_MIPS_LOCAL_H
 
 #include <linux/percpu.h>
+#include <linux/bitops.h>
 #include <asm/atomic.h>
+#include <asm/war.h>
 
-#ifdef CONFIG_32BIT
+typedef struct
+{
+	atomic_long_t a;
+} local_t;
 
-typedef atomic_t local_t;
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define LOCAL_INIT(i)	ATOMIC_INIT(i)
-#define local_read(v)	atomic_read(v)
-#define local_set(v,i)	atomic_set(v,i)
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
 
-#define local_inc(v)	atomic_inc(v)
-#define local_dec(v)	atomic_dec(v)
-#define local_add(i, v)	atomic_add(i, v)
-#define local_sub(i, v)	atomic_sub(i, v)
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
 
-#endif
+/*
+ * Same as above, but return the result value
+ */
+static __inline__ long local_add_return(long i, local_t * l)
+{
+	unsigned long result;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_add_return	\n"
+		"	addu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqzl	%0, 1b					\n"
+		"	addu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_add_return	\n"
+		"	addu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqz	%0, 1b					\n"
+		"	addu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else {
+		unsigned long flags;
 
-#ifdef CONFIG_64BIT
+		local_irq_save(flags);
+		result = l->a.counter;
+		result += i;
+		l->a.counter = result;
+		local_irq_restore(flags);
+	}
 
-typedef atomic64_t local_t;
+	return result;
+}
 
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
+static __inline__ long local_sub_return(long i, local_t * l)
+{
+	unsigned long result;
 
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long temp;
 
-#endif
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_return	\n"
+		"	subu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqzl	%0, 1b					\n"
+		"	subu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long temp;
 
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_return	\n"
+		"	subu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqz	%0, 1b					\n"
+		"	subu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		result = l->a.counter;
+		result -= i;
+		l->a.counter = result;
+		local_irq_restore(flags);
+	}
+
+	return result;
+}
 
 /*
- * Use these for per-cpu local_t variables: on some archs they are
+ * local_sub_if_positive - conditionally subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically test @l and subtract @i if @l is greater or equal than @i.
+ * The function returns the old value of @l minus @i.
+ */
+static __inline__ long local_sub_if_positive(long i, local_t * l)
+{
+	unsigned long result;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_if_positive\n"
+		"	dsubu	%0, %1, %3				\n"
+		"	bltz	%0, 1f					\n"
+			__SC	"%0, %2					\n"
+		"	.set	noreorder				\n"
+		"	beqzl	%0, 1b					\n"
+		"	 dsubu	%0, %1, %3				\n"
+		"	.set	reorder					\n"
+		"1:							\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_if_positive\n"
+		"	dsubu	%0, %1, %3				\n"
+		"	bltz	%0, 1f					\n"
+			__SC	"%0, %2					\n"
+		"	.set	noreorder				\n"
+		"	beqz	%0, 1b					\n"
+		"	 dsubu	%0, %1, %3				\n"
+		"	.set	reorder					\n"
+		"1:							\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		result = l->a.counter;
+		result -= i;
+		if (result >= 0)
+			l->a.counter = result;
+		local_irq_restore(flags);
+	}
+
+	return result;
+}
+
+#define local_cmpxchg(l, o, n) \
+	((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter),(n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_dec_return(l) local_sub_return(1,(l))
+#define local_inc_return(l) local_add_return(1,(l))
+
+/*
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
+
+/*
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+/*
+ * local_dec_and_test - decrement by 1 and test
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
+
+/*
+ * local_dec_if_positive - decrement by 1 if old value positive
+ * @l: pointer of type local_t
+ */
+#define local_dec_if_positive(l)	local_sub_if_positive(1, l)
+
+/*
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+#define local_add_negative(i,l) (local_add_return(i, (l)) < 0)
+
+/* Use these for per-cpu local_t variables: on some archs they are
  * much more efficient than these naive implementations.  Note they take
  * a variable, not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
 
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
+#define __local_inc(l)		((l)->a.counter++)
+#define __local_dec(l)		((l)->a.counter++)
+#define __local_add(i,l)	((l)->a.counter+=(i))
+#define __local_sub(i,l)	((l)->a.counter-=(i))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(l)	 	\
+	({ local_t res__;		\
+	   preempt_disable(); 		\
+	   res__ = (l);			\
+	   preempt_enable();		\
+	   res__; })
+#define cpu_local_wrap(l)		\
+	({ preempt_disable();		\
+	   l;				\
+	   preempt_enable(); })		\
+
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
 
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
-#endif /* _ASM_LOCAL_H */
+#endif /* _ARCH_MIPS_LOCAL_H */
diff --git a/include/asm-mips/ltt.h b/include/asm-mips/ltt.h
new file mode 100644
index 0000000..af0e659
--- /dev/null
+++ b/include/asm-mips/ltt.h
@@ -0,0 +1,50 @@
+/*
+ * linux/include/asm-mips/ltt.h
+ *
+ * Copyright (C) 2005, Mathieu Desnoyers
+ *
+ * MIPS definitions for tracing system
+ */
+
+#ifndef _ASM_MIPS_LTT_H
+#define _ASM_MIPS_LTT_H
+
+#define LTT_HAS_TSC
+
+/* Current arch type */
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_MIPS
+
+/* Current variant type */
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+#include <linux/ltt-core.h>
+#include <asm/timex.h>
+#include <asm/processor.h>
+
+u64 ltt_heartbeat_read_synthetic_tsc(void);
+
+/* MIPS get_cycles only returns a 32 bits TSC (see timex.h). The assumption
+ * there is that the reschedule is done every 8 seconds or so, so we must
+ * make sure there is at least an event (heartbeat) between  each TSC wrap
+ * around. We use the LTT synthetic TSC exactly for this. */
+static inline u32 ltt_get_timestamp32(void)
+{
+	return get_cycles();
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	return ltt_heartbeat_read_synthetic_tsc();
+}
+
+static inline unsigned int ltt_frequency(void)
+{
+	return mips_hpt_frequency;
+}
+
+static inline u32 ltt_freq_scale(void)
+{
+	return 1;
+}
+
+#endif //_ASM_MIPS_LTT_H
diff --git a/include/asm-mips/marker.h b/include/asm-mips/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-mips/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 9985cb7..1fca6ba 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -383,6 +383,7 @@
  */
 #define  CAUSEB_EXCCODE		2
 #define  CAUSEF_EXCCODE		(_ULCAST_(31)  <<  2)
+#define  CAUSE_EXCCODE(cause)	(((cause) & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE)
 #define  CAUSEB_IP		8
 #define  CAUSEF_IP		(_ULCAST_(255) <<  8)
 #define  CAUSEB_IP0		8
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 5e1289c..2258b7e 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -253,6 +253,58 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
 	return retval;
 }
 
+static inline unsigned long __cmpxchg_u32_local(volatile int * m,
+	unsigned long old, unsigned long new)
+{
+	__u32 retval;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	ll	%0, %2			# __cmpxchg_u32	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	.set	mips0					\n"
+		"	move	$1, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	$1, %1					\n"
+		"	beqzl	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	ll	%0, %2			# __cmpxchg_u32	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	.set	mips0					\n"
+		"	move	$1, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	$1, %1					\n"
+		"	beqz	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		retval = *m;
+		if (retval == old)
+			*m = new;
+		local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	return retval;
+}
+
 #ifdef CONFIG_64BIT
 static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
 	unsigned long new)
@@ -303,10 +355,62 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
 
 	return retval;
 }
+
+static inline unsigned long __cmpxchg_u64_local(volatile int * m,
+	unsigned long old, unsigned long new)
+{
+	__u64 retval;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	lld	%0, %2			# __cmpxchg_u64	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	move	$1, %z4					\n"
+		"	scd	$1, %1					\n"
+		"	beqzl	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	lld	%0, %2			# __cmpxchg_u64	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	move	$1, %z4					\n"
+		"	scd	$1, %1					\n"
+		"	beqz	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		retval = *m;
+		if (retval == old)
+			*m = new;
+		local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	return retval;
+}
+
 #else
 extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
 	volatile int * m, unsigned long old, unsigned long new);
 #define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
+extern unsigned long __cmpxchg_u64_local_unsupported_on_32bit_kernels(
+	volatile int * m, unsigned long old, unsigned long new);
+#define __cmpxchg_u64_local __cmpxchg_u64_local_unsupported_on_32bit_kernels
 #endif
 
 /* This function doesn't exist, so you'll get a linker error
@@ -326,7 +430,26 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
 	return old;
 }
 
-#define cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+static inline unsigned long __cmpxchg_local(volatile void * ptr,
+	unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_local(ptr, old, new);
+	case 8:
+		return __cmpxchg_u64_local(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,old,new) \
+	((__typeof__(*(ptr)))__cmpxchg((ptr), \
+		(unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+
+#define cmpxchg_local(ptr,old,new) \
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
+		(unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
 
 extern void set_handler (unsigned long offset, void *addr, unsigned long len);
 extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len);
diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h
index b80de8e..7408dea 100644
--- a/include/asm-mips/timex.h
+++ b/include/asm-mips/timex.h
@@ -53,6 +53,8 @@ static inline cycles_t get_cycles (void)
 	return read_c0_count();
 }
 
+extern unsigned int mips_hpt_frequency;
+
 #endif /* __KERNEL__ */
 
 #endif /*  _ASM_TIMEX_H */
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
index 696cff3..762f979 100644
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -334,16 +334,18 @@
 #define __NR_kexec_load			(__NR_Linux + 311)
 #define __NR_getcpu			(__NR_Linux + 312)
 #define __NR_epoll_pwait		(__NR_Linux + 313)
+#define	__NR_ltt_trace_generic		(__NR_Linux + 314)
+#define	__NR_ltt_register_generic	(__NR_Linux + 315)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls		313
+#define __NR_Linux_syscalls		315
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux			4000
-#define __NR_O32_Linux_syscalls		313
+#define __NR_O32_Linux_syscalls		315
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
@@ -624,16 +626,18 @@
 #define __NR_kexec_load			(__NR_Linux + 270)
 #define __NR_getcpu			(__NR_Linux + 271)
 #define __NR_epoll_pwait		(__NR_Linux + 272)
+#define	__NR_ltt_trace_generic		(__NR_Linux + 273)
+#define	__NR_ltt_register_generic	(__NR_Linux + 274)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls		272
+#define __NR_Linux_syscalls		274
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux			5000
-#define __NR_64_Linux_syscalls		272
+#define __NR_64_Linux_syscalls		274
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
@@ -918,16 +922,18 @@
 #define __NR_kexec_load			(__NR_Linux + 274)
 #define __NR_getcpu			(__NR_Linux + 275)
 #define __NR_epoll_pwait		(__NR_Linux + 276)
+#define	__NR_ltt_trace_generic		(__NR_Linux + 277)
+#define	__NR_ltt_register_generic	(__NR_Linux + 278)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls		276
+#define __NR_Linux_syscalls		278
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux			6000
-#define __NR_N32_Linux_syscalls		276
+#define __NR_N32_Linux_syscalls		278
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 48bf9b8..afb7cf5 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -163,7 +163,7 @@ static __inline__ int atomic_read(const atomic_t *v)
 }
 
 /* exported interface */
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
@@ -175,14 +175,21 @@ static __inline__ int atomic_read(const atomic_t *v)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_add(i,v)	((void)(__atomic_add_return( ((int)i),(v))))
@@ -270,6 +277,38 @@ atomic64_read(const atomic64_t *v)
 #define atomic64_dec_and_test(v)	(atomic64_dec_return(v) == 0)
 #define atomic64_sub_and_test(i,v)	(atomic64_sub_return((i),(v)) == 0)
 
+/* exported interface */
+#define atomic64_cmpxchg(v, o, n) \
+	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
+
 #endif /* __LP64__ */
 
 #include <asm-generic/atomic.h>
diff --git a/include/asm-parisc/local.h b/include/asm-parisc/local.h
index d0f5509..c11c530 100644
--- a/include/asm-parisc/local.h
+++ b/include/asm-parisc/local.h
@@ -1,40 +1 @@
-#ifndef _ARCH_PARISC_LOCAL_H
-#define _ARCH_PARISC_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-typedef atomic_long_t local_t;
-
-#define LOCAL_INIT(i)	ATOMIC_LONG_INIT(i)
-#define local_read(v)	atomic_long_read(v)
-#define local_set(v,i)	atomic_long_set(v,i)
-
-#define local_inc(v)	atomic_long_inc(v)
-#define local_dec(v)	atomic_long_dec(v)
-#define local_add(i, v)	atomic_long_add(i, v)
-#define local_sub(i, v)	atomic_long_sub(i, v)
-
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
-
-/* Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations.  Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ARCH_PARISC_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-parisc/ltt.h b/include/asm-parisc/ltt.h
new file mode 100644
index 0000000..07be064
--- /dev/null
+++ b/include/asm-parisc/ltt.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_PARISC_LTT_H
+#define _ASM_PARISC_LTT_H
+
+#define LTT_HAS_TSC
+
+#endif
diff --git a/include/asm-parisc/marker.h b/include/asm-parisc/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-parisc/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index f038e33..c44810b 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -11,6 +11,7 @@ typedef struct { volatile int counter; } atomic_t;
 #include <linux/compiler.h>
 #include <asm/synch.h>
 #include <asm/asm-compat.h>
+#include <asm/system.h>
 
 #define ATOMIC_INIT(i)		{ (i) }
 
@@ -165,7 +166,7 @@ static __inline__ int atomic_dec_return(atomic_t *v)
 	return t;
 }
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
@@ -413,6 +414,42 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
 	return t;
 }
 
+#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long t;
+
+	__asm__ __volatile__ (
+	LWSYNC_ON_SMP
+"1:	ldarx	%0,0,%1		# atomic_add_unless\n\
+	cmpd	0,%0,%3 \n\
+	beq-	2f \n\
+	add	%0,%2,%0 \n"
+"	stdcx.	%0,0,%1 \n\
+	bne-	1b \n"
+	ISYNC_ON_SMP
+"	subf	%0,%2,%0 \n\
+2:"
+	: "=&r" (t)
+	: "r" (&v->counter), "r" (a), "r" (u)
+	: "cc", "memory");
+
+	return t != u;
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #endif /* __powerpc64__ */
 
 #include <asm-generic/atomic.h>
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index 8f757f6..8144a27 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -39,7 +39,6 @@
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
-#include <asm/atomic.h>
 #include <asm/asm-compat.h>
 #include <asm/synch.h>
 
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index 9e4dd98..ed8ae98 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -16,6 +16,10 @@ extern void timer_interrupt(struct pt_regs *);
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 
+#ifdef CONFIG_IPIPE
+#error "I-pipe: arch/powerpc64 not supported yet - use an older Adeos patch."
+#endif
+
 static inline unsigned long local_get_flags(void)
 {
 	unsigned long flags;
@@ -51,17 +55,36 @@ extern void iseries_handle_interrupts(void);
 #define hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
 #define hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
 
-#else
+#else  /* !CONFIG_PPC64 */
+
+static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real)
+{
+	/* Merge virtual and real interrupt mask bits into a single
+	   32bit word. */
+	return (real & ~(1 << 31)) | ((virt != 0) << 31);
+}
 
+static inline int raw_demangle_irq_bits(unsigned long *x)
+{
+	int virt = (*x & (1 << 31)) != 0;
+	*x &= ~(1L << 31);
+	return virt;
+}
+
+#define local_save_flags_hw(x)			((x) = mfmsr())
+#define local_test_iflag_hw(x)			((x) & MSR_EE)
+#define irqs_disabled_hw()			((mfmsr() & MSR_EE) == 0)
+#define local_irq_save_hw_notrace(x)		local_irq_save_ptr_hw(&(x))
+#define raw_irqs_disabled_flags(x)		(!local_test_iflag_hw(x))
 #if defined(CONFIG_BOOKE)
-#define SET_MSR_EE(x)	mtmsr(x)
-#define local_irq_restore(flags)	__asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
+#define local_irq_restore_hw_notrace(x)	\
+	__asm__ __volatile__("wrtee %0" : : "r" (x) : "memory")
 #else
 #define SET_MSR_EE(x)	mtmsr(x)
-#define local_irq_restore(flags)	mtmsr(flags)
+#define local_irq_restore_hw_notrace(x)	mtmsr(x)
 #endif
 
-static inline void local_irq_disable(void)
+static inline void local_irq_disable_hw_notrace(void)
 {
 #ifdef CONFIG_BOOKE
 	__asm__ __volatile__("wrteei 0": : :"memory");
@@ -73,7 +96,7 @@ static inline void local_irq_disable(void)
 #endif
 }
 
-static inline void local_irq_enable(void)
+static inline void local_irq_enable_hw_notrace(void)
 {
 #ifdef CONFIG_BOOKE
 	__asm__ __volatile__("wrteei 1": : :"memory");
@@ -85,11 +108,11 @@ static inline void local_irq_enable(void)
 #endif
 }
 
-static inline void local_irq_save_ptr(unsigned long *flags)
+static inline void local_irq_save_ptr_hw(unsigned long *x)
 {
 	unsigned long msr;
 	msr = mfmsr();
-	*flags = msr;
+	*x = msr;
 #ifdef CONFIG_BOOKE
 	__asm__ __volatile__("wrteei 0": : :"memory");
 #else
@@ -98,9 +121,107 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 	__asm__ __volatile__("": : :"memory");
 }
 
-#define local_save_flags(flags)	((flags) = mfmsr())
-#define local_irq_save(flags)	local_irq_save_ptr(&flags)
-#define irqs_disabled()		((mfmsr() & MSR_EE) == 0)
+#ifdef CONFIG_IPIPE
+
+#include <linux/ipipe_base.h>
+#include <linux/ipipe_trace.h>
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+
+static inline void local_irq_disable_hw(void)
+{
+	if (!irqs_disabled_hw()) {
+		local_irq_disable_hw_notrace();
+		ipipe_trace_begin(0x80000000);
+	}
+}
+
+static inline void local_irq_enable_hw(void)
+{
+	if (irqs_disabled_hw()) {
+		ipipe_trace_end(0x80000000);
+		local_irq_enable_hw_notrace();
+	}
+}
+
+#define local_irq_save_hw(x) \
+do {						       \
+	local_irq_save_ptr_hw(&(x));		       \
+	if (local_test_iflag_hw(x))		       \
+		ipipe_trace_begin(0x80000001);	       \
+} while(0)
+
+static inline void local_irq_restore_hw(unsigned long x)
+{
+	if (local_test_iflag_hw(x))
+		ipipe_trace_end(0x80000001);
+
+	local_irq_restore_hw_notrace(x);
+}
+
+#else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
+
+#define local_irq_disable_hw    local_irq_disable_hw_notrace
+#define local_irq_enable_hw     local_irq_enable_hw_notrace
+#define local_irq_save_hw       local_irq_save_hw_notrace
+#define local_irq_restore_hw    local_irq_restore_hw_notrace
+
+#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
+
+static inline void local_irq_disable(void)
+{
+	ipipe_check_context(ipipe_root_domain);
+	__ipipe_stall_root();
+	barrier();
+}
+
+static inline void local_irq_enable(void)
+{
+	barrier();
+	__ipipe_unstall_root();
+}
+
+static inline void local_irq_save_ptr(unsigned long *x)
+{
+	*x = (!__ipipe_test_and_stall_root()) << MSR_EE_LG;
+	barrier();
+}
+
+static inline void local_irq_restore(unsigned long x)
+{
+	barrier();
+	__ipipe_restore_root(!(x & MSR_EE));
+}
+
+#define local_save_flags(x)			\
+do {						\
+	(x) = (!__ipipe_test_root()) << MSR_EE_LG;	\
+	barrier();				\
+} while(0)
+
+#define local_irq_save(x)			\
+do {						\
+	ipipe_check_context(ipipe_root_domain);	\
+	local_irq_save_ptr(&(x));		\
+} while(0)
+
+#define irqs_disabled()		__ipipe_test_root()
+
+#else /* !CONFIG_IPIPE */
+
+#define local_irq_disable_hw    	local_irq_disable_hw_notrace
+#define local_irq_enable_hw     	local_irq_enable_hw_notrace
+#define local_irq_save_hw       	local_irq_save_hw_notrace
+#define local_irq_restore_hw    	local_irq_restore_hw_notrace
+#define local_irq_restore(x)		local_irq_restore_hw(x)
+#define local_irq_disable()		local_irq_disable_hw()
+#define local_irq_enable()		local_irq_enable_hw()
+#define local_irq_save_ptr(x)		local_irq_save_ptr_hw(x)
+#define irqs_disabled()			irqs_disabled_hw()
+#define local_save_flags(x)		local_save_flags_hw(x)
+#define local_irq_save(x)  		local_irq_save_hw(x)
+
+#endif /* !CONFIG_IPIPE */
 
 #define hard_irq_enable()	local_irq_enable()
 #define hard_irq_disable()	local_irq_disable()
diff --git a/include/asm-powerpc/ipipe.h b/include/asm-powerpc/ipipe.h
new file mode 100644
index 0000000..1f21224
--- /dev/null
+++ b/include/asm-powerpc/ipipe.h
@@ -0,0 +1,198 @@
+/*
+ *   include/asm-powerpc/ipipe.h
+ *
+ *   I-pipe 32/64bit merge - Copyright (C) 2007 Philippe Gerum.
+ *   I-pipe PA6T support - Copyright (C) 2007 Philippe Gerum.
+ *   I-pipe 64-bit PowerPC port - Copyright (C) 2005 Heikki Lindholm.
+ *   I-pipe PowerPC support - 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 __ASM_POWERPC_IPIPE_H
+#define __ASM_POWERPC_IPIPE_H
+
+#ifdef CONFIG_IPIPE
+
+#include <asm/ptrace.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <linux/ipipe_percpu.h>
+#include <linux/list.h>
+#include <linux/cpumask.h>
+#include <linux/cache.h>
+#include <linux/threads.h>
+
+#define IPIPE_ARCH_STRING	"1.9-01"
+#define IPIPE_MAJOR_NUMBER	1
+#define IPIPE_MINOR_NUMBER	9
+#define IPIPE_PATCH_NUMBER	1
+
+#define prepare_arch_switch(next)			\
+	do {						\
+		ipipe_schedule_notify(current ,next);	\
+		local_irq_disable_hw();			\
+	} while(0)
+
+#define task_hijacked(p)						\
+	({								\
+		int __x__ = ipipe_root_domain_p;			\
+		__clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
+		if (__x__) local_irq_enable_hw();			\
+		!__x__;							\
+	})
+
+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;		/* Decrementer virtual IRQ */
+		u64 tmfreq;		/* Timebase frequency */
+	} archdep;
+};
+
+#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;							\
+ 	})
+
+#ifdef CONFIG_PPC_MERGE
+extern unsigned long tb_ticks_per_jiffy;
+#else
+extern unsigned int tb_ticks_per_jiffy;
+#endif
+
+extern unsigned long disarm_decr[];
+
+#define ipipe_cpu_freq()	(HZ * tb_ticks_per_jiffy)
+#define ipipe_tsc2ns(t)		((((unsigned long)(t)) * 1000) / (ipipe_cpu_freq() / 1000000))
+#define ipipe_tsc2us(t)						\
+	({							\
+		unsigned long long delta = (t);			\
+		do_div(delta, ipipe_cpu_freq()/1000000+1);	\
+		(unsigned long)delta;				\
+	})
+
+/* Private interface -- Internal use only */
+
+#define __ipipe_check_platform()	do { } while(0)
+#define __ipipe_enable_irq(irq)		enable_irq(irq)
+#define __ipipe_disable_irq(irq)	disable_irq(irq)
+
+void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq);
+
+static inline void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
+{
+}
+
+void __ipipe_init_platform(void);
+
+void __ipipe_enable_pipeline(void);
+
+int __ipipe_ack_irq(unsigned irq);
+
+void __ipipe_end_irq(unsigned irq);
+
+#ifdef CONFIG_SMP
+struct ipipe_ipi_struct {
+	volatile unsigned long value;
+} ____cacheline_aligned;
+
+void __ipipe_hook_critical_ipi(struct ipipe_domain *ipd);
+
+void __ipipe_register_ipi(unsigned int irq);
+#else
+#define __ipipe_hook_critical_ipi(ipd)	do { } while(0)
+#endif /* CONFIG_SMP */
+
+extern unsigned long __ipipe_decr_ticks;
+
+DECLARE_PER_CPU(unsigned long long, __ipipe_decr_next);
+
+DECLARE_PER_CPU(struct pt_regs, __ipipe_tick_regs);
+
+void __ipipe_handle_irq(int irq, struct pt_regs *regs);
+
+struct irq_desc;
+void __ipipe_ack_level_irq(unsigned irq, struct irq_desc *desc);
+void __ipipe_end_level_irq(unsigned irq, struct irq_desc *desc);
+void __ipipe_ack_edge_irq(unsigned irq, struct irq_desc *desc);
+void __ipipe_end_edge_irq(unsigned irq, struct irq_desc *desc);
+
+void __ipipe_serial_debug(const char *fmt, ...);
+
+static inline unsigned long __ipipe_ffnz(unsigned long ul)
+{
+	__asm__ __volatile__("cntlzw %0, %1":"=r"(ul):"r"(ul & (-ul)));
+	return 31 - ul;
+}
+
+/* When running handlers, enable hw interrupts for all domains but the
+ * one heading the pipeline, so that IRQs can never be significantly
+ * deferred for the latter. */
+#define __ipipe_run_isr(ipd, irq)					\
+do {									\
+	if (!__ipipe_pipeline_head_p(ipd))				\
+		local_irq_enable_hw();					\
+	if (ipd == ipipe_root_domain)					\
+		if (likely(!ipipe_virtual_irq_p(irq)))			\
+			ipd->irqs[irq].handler(irq, NULL);		\
+		else {							\
+			irq_enter();					\
+			ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie);\
+			irq_exit();					\
+		}							\
+	else {								\
+		__clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
+		ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie);	\
+		__set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
+	}								\
+	local_irq_disable_hw();						\
+} while(0)
+
+#define __ipipe_syscall_watched_p(p, sc)	\
+	(((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= NR_syscalls)
+
+#else /* !CONFIG_IPIPE */
+
+#define task_hijacked(p)	0
+
+#endif /* CONFIG_IPIPE */
+
+#endif /* !__ASM_POWERPC_IPIPE_H */
diff --git a/include/asm-powerpc/ipipe_base.h b/include/asm-powerpc/ipipe_base.h
new file mode 100644
index 0000000..6d5db8f
--- /dev/null
+++ b/include/asm-powerpc/ipipe_base.h
@@ -0,0 +1,146 @@
+/* -*- linux-c -*-
+ * include/asm-powerpc/ipipe_base.h
+ *
+ * Copyright (C) 2007 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 __ASM_POWERPC_IPIPE_BASE_H
+#define __ASM_POWERPC_IPIPE_BASE_H
+
+#define IPIPE_NR_XIRQS		NR_IRQS
+#define IPIPE_IRQ_ISHIFT	5		/* 32-bit arch. */
+
+/* 
+ * The first virtual interrupt is reserved for the timer (see
+ * __ipipe_init_platform). 
+ */
+#define IPIPE_TIMER_VIRQ	IPIPE_VIRQ_BASE
+
+#define __ipipe_tick_irq	IPIPE_TIMER_VIRQ
+
+#ifdef CONFIG_SMP
+/* 
+ * These are virtual IPI numbers. The OpenPIC supports only 4 IPIs and
+ * IPIs 0x0,0x1,0x3 are already used by Linux. The virtualization
+ * layer is implemented by using the free IPI 0x2 and cascading it in
+ * arch/powerpc/kernel/ipipe.c.
+ */
+/* these are bit numbers in practice */
+#define IPIPE_MSG_CRITICAL_IPI	0
+#define IPIPE_MSG_SERVICE_IPI0	(IPIPE_MSG_CRITICAL_IPI + 1)
+#define IPIPE_MSG_SERVICE_IPI1	(IPIPE_MSG_CRITICAL_IPI + 2)
+#define IPIPE_MSG_SERVICE_IPI2	(IPIPE_MSG_CRITICAL_IPI + 3)
+#define IPIPE_MSG_SERVICE_IPI3	(IPIPE_MSG_CRITICAL_IPI + 4)
+#define IPIPE_MSG_SERVICE_IPI4	(IPIPE_MSG_CRITICAL_IPI + 5)
+
+#define IPIPE_MSG_IPI_MASK	((1UL << IPIPE_MSG_CRITICAL_IPI) |	\
+				 (1UL << IPIPE_MSG_SERVICE_IPI0) |	\
+				 (1UL << IPIPE_MSG_SERVICE_IPI1) |	\
+				 (1UL << IPIPE_MSG_SERVICE_IPI2) |	\
+				 (1UL << IPIPE_MSG_SERVICE_IPI3) |	\
+				 (1UL << IPIPE_MSG_SERVICE_IPI4))
+
+#define IPIPE_CRITICAL_IPI	(IPIPE_VIRQ_BASE + 1)
+#define IPIPE_SERVICE_IPI0	(IPIPE_CRITICAL_IPI + 1)
+#define IPIPE_SERVICE_IPI1	(IPIPE_CRITICAL_IPI + 2)
+#define IPIPE_SERVICE_IPI2	(IPIPE_CRITICAL_IPI + 3)
+#define IPIPE_SERVICE_IPI3	(IPIPE_CRITICAL_IPI + 4)
+#define IPIPE_SERVICE_IPI4	(IPIPE_CRITICAL_IPI + 5)
+
+#define IPIPE_MSG_IPI_OFFSET	(IPIPE_CRITICAL_IPI)
+
+#define ipipe_processor_id()	raw_smp_processor_id()
+#else  /* !CONFIG_SMP */
+#define ipipe_processor_id()	0
+#endif /* CONFIG_SMP */
+
+/* traps */
+#define IPIPE_TRAP_ACCESS	 0	/* Data or instruction access exception */
+#define IPIPE_TRAP_ALIGNMENT	 1	/* Alignment exception */
+#define IPIPE_TRAP_ALTUNAVAIL	 2	/* Altivec unavailable */
+#define IPIPE_TRAP_PCE		 3	/* Program check exception */
+#define IPIPE_TRAP_MCE		 4	/* Machine check exception */
+#define IPIPE_TRAP_UNKNOWN	 5	/* Unknown exception */
+#define IPIPE_TRAP_IABR		 6	/* Instruction breakpoint */
+#define IPIPE_TRAP_RM		 7	/* Run mode exception */
+#define IPIPE_TRAP_SSTEP	 8	/* Single-step exception */
+#define IPIPE_TRAP_NREC		 9	/* Non-recoverable exception */
+#define IPIPE_TRAP_SOFTEMU	10	/* Software emulation */
+#define IPIPE_TRAP_DEBUG	11	/* Debug exception */
+#define IPIPE_TRAP_SPE		12	/* SPE exception */
+#define IPIPE_TRAP_ALTASSIST	13	/* Altivec assist exception */
+#define IPIPE_TRAP_CACHE	14	/* Cache-locking exception (FSL) */
+#define IPIPE_TRAP_KFPUNAVAIL	15	/* FP unavailable exception */
+#define IPIPE_NR_FAULTS		16
+/* Pseudo-vectors used for kernel events */
+#define IPIPE_FIRST_EVENT		IPIPE_NR_FAULTS
+#define IPIPE_EVENT_SYSCALL		(IPIPE_FIRST_EVENT)
+#define IPIPE_EVENT_SCHEDULE		(IPIPE_FIRST_EVENT + 1)
+#define IPIPE_EVENT_SIGWAKE		(IPIPE_FIRST_EVENT + 2)
+#define IPIPE_EVENT_SETSCHED		(IPIPE_FIRST_EVENT + 3)
+#define IPIPE_EVENT_INIT		(IPIPE_FIRST_EVENT + 4)
+#define IPIPE_EVENT_EXIT		(IPIPE_FIRST_EVENT + 5)
+#define IPIPE_EVENT_CLEANUP		(IPIPE_FIRST_EVENT + 6)
+#define IPIPE_LAST_EVENT		IPIPE_EVENT_CLEANUP
+#define IPIPE_NR_EVENTS			(IPIPE_LAST_EVENT + 1)
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_SMP
+
+void __ipipe_stall_root(void);
+
+unsigned long __ipipe_test_and_stall_root(void);
+
+unsigned long __ipipe_test_root(void);
+
+#else /* !CONFIG_SMP */
+
+#include <linux/bitops.h>
+
+#if __GNUC__ >= 4
+/* Alias to ipipe_root_cpudom_var(status) */
+extern unsigned long __ipipe_root_status;
+#else
+extern unsigned long *const __ipipe_root_status_addr;
+#define __ipipe_root_status	(*__ipipe_root_status_addr)
+#endif
+
+static __inline__ void __ipipe_stall_root(void)
+{
+	volatile unsigned long *p = &__ipipe_root_status;
+	set_bit(0, p);
+}
+
+static __inline__ unsigned long __ipipe_test_and_stall_root(void)
+{
+	volatile unsigned long *p = &__ipipe_root_status;
+	return test_and_set_bit(0, p);
+}
+
+static __inline__ unsigned long __ipipe_test_root(void)
+{
+	volatile unsigned long *p = &__ipipe_root_status;
+	return test_bit(0, p);
+}
+
+#endif /* !CONFIG_SMP */
+
+#endif /* !__ASSEMBLY__ */
+
+#endif	/* !__ASM_POWERPC_IPIPE_BASE_H */
diff --git a/include/asm-powerpc/local.h b/include/asm-powerpc/local.h
index c11c530..612d832 100644
--- a/include/asm-powerpc/local.h
+++ b/include/asm-powerpc/local.h
@@ -1 +1,200 @@
-#include <asm-generic/local.h>
+#ifndef _ARCH_POWERPC_LOCAL_H
+#define _ARCH_POWERPC_LOCAL_H
+
+#include <linux/percpu.h>
+#include <asm/atomic.h>
+
+typedef struct
+{
+	atomic_long_t a;
+} local_t;
+
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
+
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
+
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
+
+static __inline__ long local_add_return(long a, local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%2		# local_add_return\n\
+	add	%0,%1,%0\n"
+	PPC405_ERR77(0,%2)
+	PPC_STLCX	"%0,0,%2 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (a), "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+#define local_add_negative(a, l)	(local_add_return((a), (l)) < 0)
+
+static __inline__ long local_sub_return(long a, local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%2		# local_sub_return\n\
+	subf	%0,%1,%0\n"
+	PPC405_ERR77(0,%2)
+	PPC_STLCX	"%0,0,%2 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (a), "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+static __inline__ long local_inc_return(local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%1		# local_inc_return\n\
+	addic	%0,%0,1\n"
+	PPC405_ERR77(0,%1)
+	PPC_STLCX	"%0,0,%1 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+/*
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+static __inline__ long local_dec_return(local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%1		# local_dec_return\n\
+	addic	%0,%0,-1\n"
+	PPC405_ERR77(0,%1)
+	PPC_STLCX	"%0,0,%1\n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+static __inline__ int local_add_unless(local_t *l, long a, long u)
+{
+	long t;
+
+	__asm__ __volatile__ (
+"1:"	PPC_LLARX	"%0,0,%1		# local_add_unless\n\
+	cmpw	0,%0,%3 \n\
+	beq-	2f \n\
+	add	%0,%2,%0 \n"
+	PPC405_ERR77(0,%2)
+	PPC_STLCX	"%0,0,%1 \n\
+	bne-	1b \n"
+"	subf	%0,%2,%0 \n\
+2:"
+	: "=&r" (t)
+	: "r" (&(l->a.counter)), "r" (a), "r" (u)
+	: "cc", "memory");
+
+	return t != u;
+}
+
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_sub_and_test(a, l)	(local_sub_return((a), (l)) == 0)
+#define local_dec_and_test(l)		(local_dec_return((l)) == 0)
+
+/*
+ * Atomically test *l and decrement if it is greater than 0.
+ * The function returns the old value of *l minus 1.
+ */
+static __inline__ long local_dec_if_positive(local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%1		# local_dec_if_positive\n\
+	cmpwi	%0,1\n\
+	addi	%0,%0,-1\n\
+	blt-	2f\n"
+	PPC405_ERR77(0,%1)
+	PPC_STLCX	"%0,0,%1\n\
+	bne-	1b"
+	"\n\
+2:"	: "=&b" (t)
+	: "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+/* Use these for per-cpu local_t variables: on some archs they are
+ * much more efficient than these naive implementations.  Note they take
+ * a variable, not an address.
+ */
+
+#define __local_inc(l)		((l)->a.counter++)
+#define __local_dec(l)		((l)->a.counter++)
+#define __local_add(i,l)	((l)->a.counter+=(i))
+#define __local_sub(i,l)	((l)->a.counter-=(i))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(l)	 	\
+	({ local_t res__;		\
+	   preempt_disable(); 		\
+	   res__ = (l);			\
+	   preempt_enable();		\
+	   res__; })
+#define cpu_local_wrap(l)		\
+	({ preempt_disable();		\
+	   l;				\
+	   preempt_enable(); })		\
+
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
+
+#endif /* _ARCH_POWERPC_LOCAL_H */
diff --git a/include/asm-powerpc/ltt.h b/include/asm-powerpc/ltt.h
new file mode 100644
index 0000000..7b01aed
--- /dev/null
+++ b/include/asm-powerpc/ltt.h
@@ -0,0 +1,47 @@
+/*
+ * linux/include/asm-powerpc/ltt.h
+ *
+ * Copyright (C) 2005, Mathieu Desnoyers
+ *
+ * POWERPC definitions for tracing system
+ */
+
+#ifndef _ASM_POWERPC_LTT_H
+#define _ASM_POWERPC_LTT_H
+
+#define LTT_HAS_TSC
+
+/* Current arch type */
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_POWERPC
+
+/* Current variant type */
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+#include <linux/ltt-core.h>
+#include <asm/timex.h>
+#include <asm/time.h>
+#include <asm/processor.h>
+
+u64 ltt_heartbeat_read_synthetic_tsc(void);
+
+static inline u32 ltt_get_timestamp32(void)
+{
+	return get_tbl();
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	return get_tb();
+}
+
+static inline unsigned int ltt_frequency(void)
+{
+	return tb_ticks_per_sec;
+}
+
+static inline u32 ltt_freq_scale(void)
+{
+	return 1;
+}
+
+#endif //_ASM_POWERPC_LTT_H
diff --git a/include/asm-powerpc/marker.h b/include/asm-powerpc/marker.h
new file mode 100644
index 0000000..912a627
--- /dev/null
+++ b/include/asm-powerpc/marker.h
@@ -0,0 +1,82 @@
+#ifndef _ASM_POWERPC_MARKER_H
+#define _ASM_POWERPC_MARKER_H
+
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. PowerPC architecture
+ * optimisations.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm/asm-compat.h>
+
+#ifdef CONFIG_MARKERS
+
+#define _MF_DEFAULT (_MF_OPTIMIZED | _MF_LOCKDEP | _MF_PRINTK)
+
+/* Optimized version of the markers */
+#define MARK_OPTIMIZED(flags, name, format, args...) \
+	do { \
+		static const char __mstrtab_name_##name[] \
+		__attribute__((section("__markers_strings"))) \
+		= #name; \
+		static const char __mstrtab_format_##name[] \
+		__attribute__((section("__markers_strings"))) \
+		= format; \
+		static struct __mark_marker_data __mark_data_##name \
+		__attribute__((section("__markers_data"))) = \
+		{ __mstrtab_name_##name,  __mstrtab_format_##name, \
+		(flags) | _MF_OPTIMIZED, __mark_empty_function, NULL }; \
+		char condition; \
+		asm volatile(	".section __markers, \"a\", @progbits;\n\t" \
+					PPC_LONG "%1, 0f;\n\t" \
+					".previous;\n\t" \
+					".align 4\n\t" \
+					"0:\n\t" \
+					"li %0,0;\n\t" \
+				: "=r" (condition) \
+				: "i" (&__mark_data_##name)); \
+		__mark_check_format(format, ## args); \
+		if (unlikely(condition)) { \
+			unsigned long irqflags; \
+			ipipe_preempt_disable(irqflags); \
+			(*__mark_data_##name.call)(&__mark_data_##name, \
+						format, ## args); \
+			ipipe_preempt_enable(irqflags); \
+		} \
+	} while (0)
+
+/* Marker macro selecting the generic or optimized version of marker, depending
+ * on the flags specified. */
+#define _MARK(flags, format, args...) \
+do { \
+	if ((flags) & _MF_OPTIMIZED) \
+		MARK_OPTIMIZED(flags, format, ## args); \
+	else \
+		MARK_GENERIC(flags, format, ## args); \
+} while (0)
+
+/* Marker with default behavior */
+#define MARK(format, args...) _MARK(_MF_DEFAULT, format, ## args)
+
+/* Architecture dependant marker information, used internally for marker
+ * activation. */
+
+/* Offset of the immediate value from the start of the addi instruction (result
+ * of the li mnemonic), in bytes. */
+#define MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET 2
+#define MARK_OPTIMIZED_ENABLE_TYPE short
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define MARK_OPTIMIZED_ENABLE(a) \
+	*(MARK_OPTIMIZED_ENABLE_TYPE*) \
+		((char*)a+MARK_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET)
+
+extern int marker_optimized_set_enable(void *address, char enable);
+
+#endif
+#endif //_ASM_POWERPC_MARKER_H
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 0afee17..fbe9d33 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
+#include <asm/irq.h>
 #include <asm/atomic.h>
 
 /* Definitions used by the flattened device tree */
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 97b4354..2994770 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -305,3 +305,5 @@ SYSCALL_SPU(faccessat)
 COMPAT_SYS_SPU(get_robust_list)
 COMPAT_SYS_SPU(set_robust_list)
 COMPAT_SYS(move_pages)
+SYSCALL(ltt_trace_generic)
+SYSCALL(ltt_register_generic)
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index f7b1227..1ee9236 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 
 #include <asm/hw_irq.h>
-#include <asm/atomic.h>
 
 /*
  * Memory barrier.
@@ -226,6 +225,29 @@ __xchg_u32(volatile void *p, unsigned long val)
 	return prev;
 }
 
+/*
+ * Atomic exchange
+ *
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ */
+static __inline__ unsigned long
+__xchg_u32_local(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%3,0,%2 \n\
+	bne-	1b"
+	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
+
 #ifdef CONFIG_PPC64
 static __inline__ unsigned long
 __xchg_u64(volatile void *p, unsigned long val)
@@ -245,6 +267,23 @@ __xchg_u64(volatile void *p, unsigned long val)
 
 	return prev;
 }
+
+static __inline__ unsigned long
+__xchg_u64_local(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stdcx.	%3,0,%2 \n\
+	bne-	1b"
+	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
 #endif
 
 /*
@@ -268,12 +307,33 @@ __xchg(volatile void *ptr, unsigned long x, unsigned int size)
 	return x;
 }
 
+static __inline__ unsigned long
+__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32_local(ptr, x);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __xchg_u64_local(ptr, x);
+#endif
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
 #define xchg(ptr,x)							     \
   ({									     \
      __typeof__(*(ptr)) _x_ = (x);					     \
      (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
   })
 
+#define xchg_local(ptr,x)						     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg_local((ptr),				     \
+     		(unsigned long)_x_, sizeof(*(ptr))); 			     \
+  })
+
 #define tas(ptr) (xchg((ptr),1))
 
 /*
@@ -305,6 +365,28 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
 	return prev;
 }
 
+static __inline__ unsigned long
+__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
+			unsigned long new)
+{
+	unsigned int prev;
+
+	__asm__ __volatile__ (
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
+	cmpw	0,%0,%3\n\
+	bne-	2f\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%4,0,%2\n\
+	bne-	1b"
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+
 #ifdef CONFIG_PPC64
 static __inline__ unsigned long
 __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
@@ -327,6 +409,27 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
 
 	return prev;
 }
+
+static __inline__ unsigned long
+__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
+			unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
+	cmpd	0,%0,%3\n\
+	bne-	2f\n\
+	stdcx.	%4,0,%2\n\
+	bne-	1b"
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
 #endif
 
 /* This function doesn't exist, so you'll get a linker error
@@ -349,6 +452,22 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
 	return old;
 }
 
+static __inline__ unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+	  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_local(ptr, old, new);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __cmpxchg_u64_local(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
 #define cmpxchg(ptr,o,n)						 \
   ({									 \
      __typeof__(*(ptr)) _o_ = (o);					 \
@@ -357,6 +476,15 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+
+#define cmpxchg_local(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 #ifdef CONFIG_PPC64
 /*
  * We handle most unaligned accesses in hardware. On the other hand 
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 0ae954e..a5fddc9 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -324,10 +324,12 @@
 #define __NR_get_robust_list	299
 #define __NR_set_robust_list	300
 #define __NR_move_pages		301
+#define __NR_ltt_trace_generic	302
+#define __NR_ltt_register_generic	303
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls		302
+#define __NR_syscalls		304
 
 #define __NR__exit __NR_exit
 #define NR_syscalls	__NR_syscalls
diff --git a/include/asm-ppc/ipipe.h b/include/asm-ppc/ipipe.h
new file mode 100644
index 0000000..5bb60ef
--- /dev/null
+++ b/include/asm-ppc/ipipe.h
@@ -0,0 +1,25 @@
+/*
+ *   include/asm-ppc/ipipe.h
+ *
+ *   I-pipe 32/64bit merge - Copyright (C) 2007 Philippe Gerum.
+ *   I-pipe PA6T support - Copyright (C) 2007 Philippe Gerum.
+ *   I-pipe 64-bit PowerPC port - Copyright (C) 2005 Heikki Lindholm.
+ *   I-pipe PowerPC support - 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.
+ */
+
+#include <asm-powerpc/ipipe.h>
diff --git a/include/asm-ppc/ipipe_base.h b/include/asm-ppc/ipipe_base.h
new file mode 100644
index 0000000..4b7d127
--- /dev/null
+++ b/include/asm-ppc/ipipe_base.h
@@ -0,0 +1,22 @@
+/* -*- linux-c -*-
+ * include/asm-ppc/ipipe_base.h
+ *
+ * Copyright (C) 2007 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.
+ */
+
+#include <asm-powerpc/ipipe_base.h>
diff --git a/include/asm-ppc/ltt.h b/include/asm-ppc/ltt.h
new file mode 100644
index 0000000..c0fff02
--- /dev/null
+++ b/include/asm-ppc/ltt.h
@@ -0,0 +1,145 @@
+/*
+ * linux/include/asm-ppc/ltt.h
+ *
+ * Copyright (C)	2002, Karim Yaghmour
+ *		 	2005, Mathieu Desnoyers
+ *
+ * PowerPC definitions for tracing system
+ */
+
+#ifndef _ASM_PPC_LTT_H
+#define _ASM_PPC_LTT_H
+
+#include <linux/jiffies.h>
+#include <asm/reg.h>
+#include <asm-ppc/time.h>
+
+/* Current arch type */
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_PPC
+
+/* PowerPC variants */
+#define LTT_ARCH_VARIANT_PPC_4xx 1	/* 4xx systems (IBM embedded series) */
+#define LTT_ARCH_VARIANT_PPC_6xx 2	/* 6xx/7xx/74xx/8260/POWER3 systems
+					   (desktop flavor) */
+#define LTT_ARCH_VARIANT_PPC_8xx 3	/* 8xx system (Motoral embedded series)
+					 */
+#define LTT_ARCH_VARIANT_PPC_ISERIES 4	/* 8xx system (iSeries) */
+
+/* Current variant type */
+#if defined(CONFIG_4xx)
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_4xx
+#elif defined(CONFIG_6xx)
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_6xx
+#elif defined(CONFIG_8xx)
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_8xx
+#elif defined(CONFIG_PPC_ISERIES)
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_ISERIES
+#else
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+#endif
+
+#define LTTNG_LOGICAL_SHIFT 13
+
+extern atomic_t lttng_logical_clock;
+
+
+/* The shift overflow doesn't matter */
+static inline u32 _ltt_get_timestamp32(void)
+{	
+	unsigned long seq;
+	unsigned long try = 5;
+	u32 ret;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		ret = (jiffies << LTTNG_LOGICAL_SHIFT) 
+			| (atomic_add_return(1, &lttng_logical_clock));
+	} while (read_seqretry(&xtime_lock, seq) && (--try) > 0);
+
+	if (try == 0)
+		return 0;
+	else
+		return ret;
+}
+
+static inline void _ltt_get_tb32(u32 *p)
+{
+	unsigned lo;
+	asm volatile("mftb %0"
+		 : "=r" (lo));
+	p[0] = lo;
+}
+
+static inline u32 ltt_get_timestamp32(void)
+{
+	u32 ret;
+	if (__is_processor(1))
+		ret = _ltt_get_timestamp32();
+	else
+		_ltt_get_tb32((u32*)&ret);
+	return ret;
+}
+
+/* The shift overflow doesn't matter */
+static inline u64 _ltt_get_timestamp64(void)
+{	
+	unsigned long seq;
+	unsigned long try = 5;
+	u64 ret;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		ret = (jiffies_64 << LTTNG_LOGICAL_SHIFT) 
+			| (atomic_add_return(1, &lttng_logical_clock));
+	} while (read_seqretry(&xtime_lock, seq) && (--try) > 0);
+
+	if (try == 0)
+		return 0;
+	else
+		return ret;
+}
+
+/* from arch/ppc/xmon/xmon.c */
+static inline void _ltt_get_tb64(unsigned *p)
+{
+	unsigned hi, lo, hiagain;
+
+	do {
+		asm volatile("mftbu %0; mftb %1; mftbu %2"
+			 : "=r" (hi), "=r" (lo), "=r" (hiagain));
+	} while (hi != hiagain);
+	p[0] = hi;
+	p[1] = lo;
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	u64 ret;
+	if (__is_processor(1))
+  		ret = _ltt_get_timestamp64();
+	else
+		_ltt_get_tb64((unsigned*)&ret);
+	return ret;
+}
+
+/* this has to be called with the write seqlock held */
+static inline void ltt_reset_timestamp(void)
+{
+	if (__is_processor(1))
+		atomic_set(&lttng_logical_clock, 0);
+}
+
+static inline unsigned int ltt_frequency(void)
+{
+	if (__is_processor(1))
+		return HZ << LTTNG_LOGICAL_SHIFT;
+	else
+		return (tb_ticks_per_jiffy * HZ);
+}
+
+static inline u32 ltt_freq_scale(void)
+{
+	return 1;
+}
+
+#endif //_ASM_PPC_LTT_H
diff --git a/include/asm-ppc/marker.h b/include/asm-ppc/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-ppc/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index 2bc8589..c80055a 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -153,7 +153,10 @@ static inline int init_new_context(struct task_struct *t, struct mm_struct *mm)
  */
 static inline void destroy_context(struct mm_struct *mm)
 {
+	unsigned long flags;
+
 	preempt_disable();
+	local_irq_save_hw_cond(flags);
 	if (mm->context.id != NO_CONTEXT) {
 		clear_bit(mm->context.id, context_map);
 		mm->context.id = NO_CONTEXT;
@@ -161,12 +164,14 @@ static inline void destroy_context(struct mm_struct *mm)
 		atomic_inc(&nr_free_contexts);
 #endif
 	}
+ 	local_irq_restore_hw_cond(flags);
 	preempt_enable();
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 			     struct task_struct *tsk)
 {
+	unsigned long flags;
 #ifdef CONFIG_ALTIVEC
 	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 	asm volatile ("dssall;\n"
@@ -176,15 +181,21 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	 : : );
 #endif /* CONFIG_ALTIVEC */
 
+ 	local_irq_save_hw_cond(flags);
+
 	tsk->thread.pgdir = next->pgd;
 
 	/* No need to flush userspace segments if the mm doesnt change */
-	if (prev == next)
+	if (prev == next) {
+		local_irq_restore_hw_cond(flags);
 		return;
+	}
 
 	/* Setup new userspace context */
 	get_mmu_context(next);
 	set_context(next->context.id, next->pgd);
+
+ 	local_irq_restore_hw_cond(flags);
 }
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h
index 16dbc7d..a722dd8 100644
--- a/include/asm-ppc/ocp.h
+++ b/include/asm-ppc/ocp.h
@@ -32,6 +32,7 @@
 #include <asm/ocp_ids.h>
 #include <asm/rwsem.h>
 #include <asm/semaphore.h>
+#include <asm/io.h>
 
 #ifdef CONFIG_PPC_OCP
 
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 7389435..4902884 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -6,7 +6,6 @@
 
 #include <linux/kernel.h>
 
-#include <asm/atomic.h>
 #include <asm/hw_irq.h>
 
 /*
@@ -169,7 +168,27 @@ xchg_u32(volatile void *p, unsigned long val)
  */
 extern void __xchg_called_with_bad_pointer(void);
 
+static __inline__ unsigned long
+__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return xchg_u32(ptr, x);
+#if 0
+	case 8:
+		return __xchg_u64_local(ptr, x);
+#endif
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define xchg_local(ptr,x)						     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg_local((ptr),				     \
+     		(unsigned long)_x_, sizeof(*(ptr))); 			     \
+  })
 #define tas(ptr) (xchg((ptr),1))
 
 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
@@ -246,6 +265,31 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+
+static __inline__ unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+	  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32(ptr, old, new);
+#if 0
+	case 8:
+		return __cmpxchg_u64_local(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg_local(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 #define arch_align_stack(x) (x)
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
index af20c74..c17bdbf 100644
--- a/include/asm-s390/atomic.h
+++ b/include/asm-s390/atomic.h
@@ -215,6 +215,8 @@ static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v)
 	       __CSG_LOOP(v, mask, "ogr");
 }
 
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
 static __inline__ long long atomic64_cmpxchg(atomic64_t *v,
 					     long long old, long long new)
 {
diff --git a/include/asm-s390/local.h b/include/asm-s390/local.h
index 86745a1..c11c530 100644
--- a/include/asm-s390/local.h
+++ b/include/asm-s390/local.h
@@ -1,58 +1 @@
-#ifndef _ASM_LOCAL_H
-#define _ASM_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-#ifndef __s390x__
-
-typedef atomic_t local_t;
-
-#define LOCAL_INIT(i)	ATOMIC_INIT(i)
-#define local_read(v)	atomic_read(v)
-#define local_set(v,i)	atomic_set(v,i)
-
-#define local_inc(v)	atomic_inc(v)
-#define local_dec(v)	atomic_dec(v)
-#define local_add(i, v)	atomic_add(i, v)
-#define local_sub(i, v)	atomic_sub(i, v)
-
-#else
-
-typedef atomic64_t local_t;
-
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
-
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
-
-#endif
-
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
-
-/*
- * Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations.  Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ASM_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-s390/ltt.h b/include/asm-s390/ltt.h
new file mode 100644
index 0000000..ad1c646
--- /dev/null
+++ b/include/asm-s390/ltt.h
@@ -0,0 +1,20 @@
+/*
+ * linux/include/asm-s390/ltt.h
+ *
+ * Copyright (C) 2002, Karim Yaghmour
+ *
+ * S/390 definitions for tracing system
+ */
+
+#ifndef _ASM_S390_LTT_H
+#define _ASM_S390_LTT_H
+
+#define LTT_HAS_TSC
+
+/* Current arch type */
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_S390
+
+/* Current variant type */
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+#endif//_ASM_S390_LTT_H
diff --git a/include/asm-s390/marker.h b/include/asm-s390/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-s390/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-sh/ltt.h b/include/asm-sh/ltt.h
new file mode 100644
index 0000000..6907e41
--- /dev/null
+++ b/include/asm-sh/ltt.h
@@ -0,0 +1,14 @@
+/*
+ * linux/include/asm-sh/ltt.h
+ *
+ * Copyright (C) 2002, Karim Yaghmour
+ *
+ * SuperH definitions for tracing system
+ */
+
+#ifndef _ASM_SH_LTT_H
+#define _ASM_SH_LTT_H
+
+#include <asm-generic/ltt.h>
+
+#endif
diff --git a/include/asm-sh/marker.h b/include/asm-sh/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-sh/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index 879f741..814e8ab 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -103,6 +103,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
+#define TIF_SYSCALL_AUDIT	5	/* syscall audit active */
 #define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		18
@@ -113,6 +114,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_USEDFPU		(1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_FREEZE		(1<<TIF_FREEZE)
diff --git a/include/asm-sh64/ltt.h b/include/asm-sh64/ltt.h
new file mode 100644
index 0000000..493c81c
--- /dev/null
+++ b/include/asm-sh64/ltt.h
@@ -0,0 +1,14 @@
+/*
+ * linux/include/asm-sh64/ltt.h
+ *
+ * Copyright (C) 2002, Karim Yaghmour
+ *
+ * SuperH definitions for tracing system
+ */
+
+#ifndef _ASM_SH_LTT_H
+#define _ASM_SH_LTT_H
+
+#include <asm-generic/ltt.h>
+
+#endif
diff --git a/include/asm-sh64/marker.h b/include/asm-sh64/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-sh64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-sh64/thread_info.h b/include/asm-sh64/thread_info.h
index 1f825cb..dcb150d 100644
--- a/include/asm-sh64/thread_info.h
+++ b/include/asm-sh64/thread_info.h
@@ -75,6 +75,7 @@ static inline struct thread_info *current_thread_info(void)
 
 /* thread information flags */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_SYSCALL_AUDIT	1	/* syscall audit active */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_MEMDIE		4
diff --git a/include/asm-sparc/ltt.h b/include/asm-sparc/ltt.h
new file mode 100644
index 0000000..78fd5ff
--- /dev/null
+++ b/include/asm-sparc/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_SPARC_LTT_H
+#define _ASM_SPARC_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-sparc/marker.h b/include/asm-sparc/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-sparc/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-sparc/thread_info.h b/include/asm-sparc/thread_info.h
index 91b9f58..1b51bcf 100644
--- a/include/asm-sparc/thread_info.h
+++ b/include/asm-sparc/thread_info.h
@@ -128,7 +128,7 @@ BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *)
  * thread information flag bit numbers
  */
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
-/* flag bit 1 is available */
+#define TIF_SYSCALL_AUDIT	1	/* syscall audit active */
 #define TIF_SIGPENDING		2	/* signal pending */
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
@@ -140,6 +140,7 @@ BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *)
 
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h
index 2f0bec2..3fb4e1f 100644
--- a/include/asm-sparc64/atomic.h
+++ b/include/asm-sparc64/atomic.h
@@ -9,6 +9,7 @@
 #define __ARCH_SPARC64_ATOMIC__
 
 #include <linux/types.h>
+#include <asm/system.h>
 
 typedef struct { volatile int counter; } atomic_t;
 typedef struct { volatile __s64 counter; } atomic64_t;
@@ -70,25 +71,47 @@ extern int atomic64_sub_ret(int, atomic64_t *);
 #define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
 #define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0)
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	likely(c != (u));					\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+#define atomic64_cmpxchg(v, o, n) \
+	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 /* Atomic operations are already serializing */
 #ifdef CONFIG_SMP
 #define smp_mb__before_atomic_dec()	membar_storeload_loadload();
diff --git a/include/asm-sparc64/local.h b/include/asm-sparc64/local.h
index dfde115..c11c530 100644
--- a/include/asm-sparc64/local.h
+++ b/include/asm-sparc64/local.h
@@ -1,40 +1 @@
-#ifndef _ARCH_SPARC64_LOCAL_H
-#define _ARCH_SPARC64_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-typedef atomic64_t local_t;
-
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
-
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
-
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
-
-/* Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations.  Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ARCH_SPARC64_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-sparc64/ltt.h b/include/asm-sparc64/ltt.h
new file mode 100644
index 0000000..1539983
--- /dev/null
+++ b/include/asm-sparc64/ltt.h
@@ -0,0 +1,15 @@
+#ifndef _ASM_SPARC64_LTT_H
+#define _ASM_SPARC64_LTT_H
+/*
+ * linux/include/asm-sparc64/ltt.h
+ *
+ * Copyright (C) 2005 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * sparc64 time and TSC definitions for ltt
+ */
+
+#define LTT_HAS_TSC
+
+#endif
diff --git a/include/asm-sparc64/marker.h b/include/asm-sparc64/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-sparc64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h
index 7af1e11..349d1d3 100644
--- a/include/asm-sparc64/tlb.h
+++ b/include/asm-sparc64/tlb.h
@@ -2,6 +2,7 @@
 #define _SPARC64_TLB_H
 
 #include <linux/swap.h>
+#include <linux/pagemap.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
diff --git a/include/asm-um/ltt.h b/include/asm-um/ltt.h
new file mode 100644
index 0000000..f38e3a7
--- /dev/null
+++ b/include/asm-um/ltt.h
@@ -0,0 +1,13 @@
+/*
+ * linux/include/asm-um/ltt.h
+ *
+ * Copyright (C) 2002, Karim Yaghmour
+ * 
+ */
+
+#ifndef _ASM_SH_LTT_H
+#define _ASM_SH_LTT_H
+
+#include <asm-generic/ltt.h>
+
+#endif
diff --git a/include/asm-um/marker.h b/include/asm-um/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-um/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-v850/ltt.h b/include/asm-v850/ltt.h
new file mode 100644
index 0000000..88d9ba3
--- /dev/null
+++ b/include/asm-v850/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_V850_LTT_H
+#define _ASM_V850_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-v850/marker.h b/include/asm-v850/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-v850/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h
index 706ca4b..19e0c60 100644
--- a/include/asm-x86_64/atomic.h
+++ b/include/asm-x86_64/atomic.h
@@ -2,6 +2,7 @@
 #define __ARCH_X86_64_ATOMIC__
 
 #include <asm/alternative.h>
+#include <asm/system.h>
 
 /* atomic_t should be 32 bit signed type */
 
@@ -375,8 +376,8 @@ static __inline__ long atomic64_add_return(long i, atomic64_t *v)
 	long __i = i;
 	__asm__ __volatile__(
 		LOCK_PREFIX "xaddq %0, %1;"
-		:"=r"(i)
-		:"m"(v->counter), "0"(i));
+		:"+r" (i), "+m" (v->counter)
+		: : "memory");
 	return i + __i;
 }
 
@@ -388,7 +389,10 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t *v)
 #define atomic64_inc_return(v)  (atomic64_add_return(1,v))
 #define atomic64_dec_return(v)  (atomic64_sub_return(1,v))
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
@@ -400,22 +404,49 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t *v)
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 /* These are x86-specific, used by some header files */
 #define atomic_clear_mask(mask, addr) \
 __asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \
diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h
index e769e62..e87492b 100644
--- a/include/asm-x86_64/local.h
+++ b/include/asm-x86_64/local.h
@@ -2,49 +2,183 @@
 #define _ARCH_X8664_LOCAL_H
 
 #include <linux/percpu.h>
+#include <asm/atomic.h>
 
 typedef struct
 {
-	volatile long counter;
+	atomic_long_t a;
 } local_t;
 
-#define LOCAL_INIT(i)	{ (i) }
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define local_read(v)	((v)->counter)
-#define local_set(v,i)	(((v)->counter) = (i))
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
 
-static inline void local_inc(local_t *v)
+static inline void local_inc(local_t *l)
 {
 	__asm__ __volatile__(
 		"incq %0"
-		:"=m" (v->counter)
-		:"m" (v->counter));
+		:"=m" (l->a.counter)
+		:"m" (l->a.counter));
 }
 
-static inline void local_dec(local_t *v)
+static inline void local_dec(local_t *l)
 {
 	__asm__ __volatile__(
 		"decq %0"
-		:"=m" (v->counter)
-		:"m" (v->counter));
+		:"=m" (l->a.counter)
+		:"m" (l->a.counter));
 }
 
-static inline void local_add(long i, local_t *v)
+static inline void local_add(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"addq %1,%0"
-		:"=m" (v->counter)
-		:"ir" (i), "m" (v->counter));
+		:"=m" (l->a.counter)
+		:"ir" (i), "m" (l->a.counter));
 }
 
-static inline void local_sub(long i, local_t *v)
+static inline void local_sub(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"subq %1,%0"
-		:"=m" (v->counter)
-		:"ir" (i), "m" (v->counter));
+		:"=m" (l->a.counter)
+		:"ir" (i), "m" (l->a.counter));
 }
 
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer to type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_sub_and_test(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"subq %2,%0; sete %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"ir" (i), "m" (l->a.counter) : "memory");
+	return c;
+}
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer to type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+static __inline__ int local_dec_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"decq %0; sete %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"m" (l->a.counter) : "memory");
+	return c != 0;
+}
+
+/**
+ * local_inc_and_test - increment and test
+ * @l: pointer to type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_inc_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"incq %0; sete %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"m" (l->a.counter) : "memory");
+	return c != 0;
+}
+
+/**
+ * local_add_negative - add and test if negative
+ * @i: integer value to add
+ * @l: pointer to type local_t
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+static __inline__ int local_add_negative(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"addq %2,%0; sets %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"ir" (i), "m" (l->a.counter) : "memory");
+	return c;
+}
+
+/**
+ * local_add_return - add and return
+ * @i: integer value to add
+ * @l: pointer to type local_t
+ *
+ * Atomically adds @i to @l and returns @i + @l
+ */
+static __inline__ long local_add_return(long i, local_t *l)
+{
+	long __i = i;
+	__asm__ __volatile__(
+		"xaddq %0, %1;"
+		:"+r" (i), "+m" (l->a.counter)
+		: : "memory");
+	return i + __i;
+}
+
+static __inline__ long local_sub_return(long i, local_t *l)
+{
+	return local_add_return(-i,l);
+}
+
+#define local_inc_return(l)  (local_add_return(1,l))
+#define local_dec_return(l)  (local_sub_return(1,l))
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+/* Always has a lock prefix */
+#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+
+/**
+ * atomic_up_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	for (;;) {						\
+		if (unlikely(c == (u)))				\
+			break;					\
+		old = local_cmpxchg((l), c, c + (a));	\
+		if (likely(old == c))				\
+			break;					\
+		c = old;					\
+	}							\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
 /* On x86-64 these are better than the atomic variants on SMP kernels
    because they dont use a lock prefix. */
 #define __local_inc(l)		local_inc(l)
@@ -62,27 +196,27 @@ static inline void local_sub(long i, local_t *v)
 
 /* Need to disable preemption for the cpu local counters otherwise we could
    still access a variable of a previous CPU in a non atomic way. */
-#define cpu_local_wrap_v(v)	 	\
+#define cpu_local_wrap_v(l)	 	\
 	({ local_t res__;		\
 	   preempt_disable(); 		\
-	   res__ = (v);			\
+	   res__ = (l);			\
 	   preempt_enable();		\
 	   res__; })
-#define cpu_local_wrap(v)		\
+#define cpu_local_wrap(l)		\
 	({ preempt_disable();		\
-	   v;				\
+	   l;				\
 	   preempt_enable(); })		\
 
-#define cpu_local_read(v)    cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
-#define cpu_local_set(v, i)  cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
-#define cpu_local_inc(v)     cpu_local_wrap(local_inc(&__get_cpu_var(v)))
-#define cpu_local_dec(v)     cpu_local_wrap(local_dec(&__get_cpu_var(v)))
-#define cpu_local_add(i, v)  cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
-#define cpu_local_sub(i, v)  cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
 
-#define __cpu_local_inc(v)	cpu_local_inc(v)
-#define __cpu_local_dec(v)	cpu_local_dec(v)
-#define __cpu_local_add(i, v)	cpu_local_add((i), (v))
-#define __cpu_local_sub(i, v)	cpu_local_sub((i), (v))
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
-#endif /* _ARCH_I386_LOCAL_H */
+#endif /* _ARCH_X8664_LOCAL_H */
diff --git a/include/asm-x86_64/ltt.h b/include/asm-x86_64/ltt.h
new file mode 100644
index 0000000..d6798d5
--- /dev/null
+++ b/include/asm-x86_64/ltt.h
@@ -0,0 +1,97 @@
+#ifndef _ASM_X86_64_LTT_H
+#define _ASM_X86_64_LTT_H
+/*
+ * linux/include/asm-x86_64/ltt.h
+ *
+ * x86_64 time and TSC definitions for ltt
+ */
+
+#include <asm/timex.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_X86_64
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+/* Minimum duration of a probe, in cycles */
+#define LTT_MIN_PROBE_DURATION 200
+
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+u64 ltt_heartbeat_read_synthetic_tsc(void);
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+
+#ifdef CONFIG_LTT_TEST_TSC
+extern cycles_t ltt_last_tsc;
+extern int ltt_tsc_is_sync;
+
+/* Support for architectures with non-sync TSCs.
+ * When the local TSC is discovered to lag behind the highest TSC counter, we
+ * increment the TSC count of an amount that should be, ideally, lower than the
+ * execution time of this routine, in cycles : this is the granularity we look
+ * for : we must be able to order the events. */
+static inline cycles_t ltt_async_tsc_read(void)
+{
+	cycles_t new_tsc;
+	cycles_t last_tsc;
+
+	new_tsc = get_cycles_sync();
+	do {
+		last_tsc = ltt_last_tsc;
+		if (new_tsc < last_tsc)
+			new_tsc = last_tsc + LTT_MIN_PROBE_DURATION;
+		/* If cmpxchg fails with a value higher than the new_tsc, don't
+		 * retry : the value has been incremented and the events
+		 * happened almost at the same time.
+		 * We must retry if cmpxchg fails with a lower value :
+		 * it means that we are the CPU with highest frequency and
+		 * therefore MUST update the value.
+		 */
+	} while (cmpxchg(&ltt_last_tsc, last_tsc, new_tsc) < new_tsc);
+	return new_tsc;
+}
+
+static inline u32 ltt_get_timestamp32(void)
+{
+	if (ltt_tsc_is_sync)
+		return (u32)get_cycles(); /* only need the 32 LSB */
+	else
+		return (u32)ltt_async_tsc_read();
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	if (ltt_tsc_is_sync)
+		return get_cycles();
+	else
+		return ltt_async_tsc_read();
+}
+#else //CONFIG_LTT_TEST_TSC
+static inline u32 ltt_get_timestamp32(void)
+{
+	return (u32)get_cycles(); /* only need the 32 LSB */
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	return get_cycles();
+}
+#endif //CONFIG_LTT_TEST_TSC
+
+
+static inline void ltt_reset_timestamp(void)
+{
+	/* FIXME : eventually do a periodic IPI to have an upper bound on
+	 * the TSC inaccuracy */
+}
+
+static inline unsigned int ltt_frequency(void)
+{
+	return cpu_khz;
+}
+
+static inline u32 ltt_freq_scale(void)
+{
+	return 1000;
+}
+
+#endif //_ASM_X86_64_LTT_H
diff --git a/include/asm-x86_64/marker.h b/include/asm-x86_64/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-x86_64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index bd376bc..9ff6e60 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -209,9 +209,45 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 	return old;
 }
 
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+			unsigned long old, unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__("cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__("cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__("cmpxchgl %k1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 8:
+		__asm__ __volatile__("cmpxchgq %1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
 #define cmpxchg(ptr,o,n)\
 	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg_local(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
 
 #ifdef CONFIG_SMP
 #define smp_mb()	mb()
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index c5f596e..1d10bda 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -619,8 +619,12 @@ __SYSCALL(__NR_sync_file_range, sys_sync_file_range)
 __SYSCALL(__NR_vmsplice, sys_vmsplice)
 #define __NR_move_pages		279
 __SYSCALL(__NR_move_pages, sys_move_pages)
+#define __NR_ltt_trace_generic		280
+__SYSCALL(__NR_ltt_trace_generic,	sys_ltt_trace_generic)
+#define __NR_ltt_register_generic		281
+__SYSCALL(__NR_ltt_register_generic,	sys_ltt_register_generic)
 
-#define __NR_syscall_max __NR_move_pages
+#define __NR_syscall_max __NR_ltt_register_generic
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-xtensa/ltt.h b/include/asm-xtensa/ltt.h
new file mode 100644
index 0000000..8406f51
--- /dev/null
+++ b/include/asm-xtensa/ltt.h
@@ -0,0 +1,5 @@
+#ifndef _ASM_XTENSA_LTT_H
+#define _ASM_XTENSA_LTT_H
+
+#include <asm-generic/ltt.h>
+#endif
diff --git a/include/asm-xtensa/marker.h b/include/asm-xtensa/marker.h
new file mode 100644
index 0000000..8d9467f
--- /dev/null
+++ b/include/asm-xtensa/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 612472a..2b2574c 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -128,7 +128,7 @@ static inline void account_system_vtime(struct task_struct *tsk)
  */
 extern void irq_exit(void);
 
-#define nmi_enter()		do { lockdep_off(); irq_enter(); } while (0)
-#define nmi_exit()		do { __irq_exit(); lockdep_on(); } while (0)
+#define nmi_enter()		do { if (ipipe_root_domain_p) { lockdep_off(); irq_enter(); } } while (0)
+#define nmi_exit()		do { if (ipipe_root_domain_p) { __irq_exit(); lockdep_on(); } } while (0)
 
 #endif /* LINUX_HARDIRQ_H */
diff --git a/include/linux/ipipe.h b/include/linux/ipipe.h
new file mode 100644
index 0000000..a2e4b0d
--- /dev/null
+++ b/include/linux/ipipe.h
@@ -0,0 +1,575 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe.h
+ *
+ * Copyright (C) 2002-2007 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_IPIPE_H
+#define __LINUX_IPIPE_H
+
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/percpu.h>
+#include <linux/mutex.h>
+#include <linux/linkage.h>
+#include <linux/ipipe_base.h>
+#include <linux/ipipe_compat.h>
+#include <asm/ipipe.h>
+
+#ifdef CONFIG_IPIPE
+/*
+ * Sanity check: IPIPE_VIRQ_BASE depends on CONFIG_NR_CPUS, and if the
+ * latter gets too large, we fail to map the virtual interrupts.
+ */
+#if IPIPE_VIRQ_BASE / BITS_PER_LONG > BITS_PER_LONG
+#error "CONFIG_NR_CPUS is too large, please lower it."
+#endif
+
+#define IPIPE_VERSION_STRING	IPIPE_ARCH_STRING
+#define IPIPE_RELEASE_NUMBER	((IPIPE_MAJOR_NUMBER << 16) | \
+				 (IPIPE_MINOR_NUMBER <<  8) | \
+				 (IPIPE_PATCH_NUMBER))
+
+#ifndef BROKEN_BUILTIN_RETURN_ADDRESS
+#define __BUILTIN_RETURN_ADDRESS0 ((unsigned long)__builtin_return_address(0))
+#define __BUILTIN_RETURN_ADDRESS1 ((unsigned long)__builtin_return_address(1))
+#endif /* !BUILTIN_RETURN_ADDRESS */
+
+#define IPIPE_ROOT_PRIO		100
+#define IPIPE_ROOT_ID		0
+#define IPIPE_ROOT_NPTDKEYS	4	/* Must be <= BITS_PER_LONG */
+
+#define IPIPE_RESET_TIMER	0x1
+#define IPIPE_GRAB_TIMER	0x2
+
+/* Global domain flags */
+#define IPIPE_SPRINTK_FLAG	0	/* Synchronous printk() allowed */
+#define IPIPE_AHEAD_FLAG	1	/* Domain always heads the pipeline */
+
+/* Interrupt control bits */
+#define IPIPE_HANDLE_FLAG	0
+#define IPIPE_PASS_FLAG		1
+#define IPIPE_ENABLE_FLAG	2
+#define IPIPE_DYNAMIC_FLAG	IPIPE_HANDLE_FLAG
+#define IPIPE_STICKY_FLAG	3
+#define IPIPE_SYSTEM_FLAG	4
+#define IPIPE_LOCK_FLAG		5
+#define IPIPE_WIRED_FLAG	6
+#define IPIPE_EXCLUSIVE_FLAG	7
+
+#define IPIPE_HANDLE_MASK	(1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK		(1 << IPIPE_PASS_FLAG)
+#define IPIPE_ENABLE_MASK	(1 << IPIPE_ENABLE_FLAG)
+#define IPIPE_DYNAMIC_MASK	IPIPE_HANDLE_MASK
+#define IPIPE_STICKY_MASK	(1 << IPIPE_STICKY_FLAG)
+#define IPIPE_SYSTEM_MASK	(1 << IPIPE_SYSTEM_FLAG)
+#define IPIPE_LOCK_MASK		(1 << IPIPE_LOCK_FLAG)
+#define IPIPE_WIRED_MASK	(1 << IPIPE_WIRED_FLAG)
+#define IPIPE_EXCLUSIVE_MASK	(1 << IPIPE_EXCLUSIVE_FLAG)
+
+#define IPIPE_DEFAULT_MASK	(IPIPE_HANDLE_MASK|IPIPE_PASS_MASK)
+#define IPIPE_STDROOT_MASK	(IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_SYSTEM_MASK)
+
+#define IPIPE_EVENT_SELF        0x80000000
+
+#define IPIPE_NR_CPUS		NR_CPUS
+
+#define ipipe_current_domain	ipipe_cpu_var(ipipe_percpu_domain)
+
+#define ipipe_virtual_irq_p(irq)	((irq) >= IPIPE_VIRQ_BASE && \
+					 (irq) < IPIPE_NR_IRQS)
+
+#define IPIPE_SAME_HANDLER	((ipipe_irq_handler_t)(-1))
+
+typedef int (*ipipe_irq_ackfn_t)(unsigned irq);
+
+typedef int (*ipipe_event_handler_t)(unsigned event,
+				     struct ipipe_domain *from,
+				     void *data);
+struct ipipe_domain {
+
+	int slot;			/* Slot number in percpu domain data array. */
+	struct list_head p_link;	/* Link in pipeline */
+	ipipe_event_handler_t evhand[IPIPE_NR_EVENTS]; /* Event handlers. */
+	unsigned long long evself;	/* Self-monitored event bits. */
+
+	struct {
+		unsigned long control;
+		ipipe_irq_ackfn_t acknowledge;
+		ipipe_irq_handler_t handler;
+		void *cookie;
+	} ____cacheline_aligned irqs[IPIPE_NR_IRQS];
+
+	int priority;
+	void *pdd;
+	unsigned long flags;
+	unsigned domid;
+	const char *name;
+	struct mutex mutex;
+};
+
+#define IPIPE_HEAD_PRIORITY	(-1) /* For domains always heading the pipeline */
+
+struct ipipe_domain_attr {
+
+	unsigned domid;		/* Domain identifier -- Magic value set by caller */
+	const char *name;	/* Domain name -- Warning: won't be dup'ed! */
+	int priority;		/* Priority in interrupt pipeline */
+	void (*entry) (void);	/* Domain entry point */
+	void *pdd;		/* Per-domain (opaque) data pointer */
+};
+
+#ifdef CONFIG_SMP
+/* These ops must start and complete on the same CPU: care for
+ * migration. */
+#define set_bit_safe(b, a)						\
+		({ unsigned long __flags;				\
+		local_irq_save_hw_notrace(__flags);			\
+		__set_bit(b, a);					\
+		local_irq_restore_hw_notrace(__flags); })
+#define test_and_set_bit_safe(b, a)					\
+		({ unsigned long __flags, __x;				\
+		local_irq_save_hw_notrace(__flags);			\
+		__x = __test_and_set_bit(b, a);				\
+		local_irq_restore_hw_notrace(__flags); __x; })
+#define clear_bit_safe(b, a)						\
+		({ unsigned long __flags;				\
+		local_irq_save_hw_notrace(__flags);			\
+		__clear_bit(b, a);					\
+		local_irq_restore_hw_notrace(__flags); })
+#else
+#define set_bit_safe(b, a)		set_bit(b, a)
+#define test_and_set_bit_safe(b, a)	test_and_set_bit(b, a)
+#define clear_bit_safe(b, a)		clear_bit(b, a)
+#endif
+
+#define __ipipe_irq_cookie(ipd, irq)		(ipd)->irqs[irq].cookie
+#define __ipipe_irq_handler(ipd, irq)		(ipd)->irqs[irq].handler
+#define __ipipe_cpudata_irq_hits(ipd, cpu, irq)	ipipe_percpudom(ipd, irqall, cpu)[irq]
+
+extern unsigned __ipipe_printk_virq;
+
+extern unsigned long __ipipe_virtual_irq_map;
+
+extern struct list_head __ipipe_pipeline;
+
+extern int __ipipe_event_monitors[];
+
+/* Private interface */
+
+void ipipe_init(void);
+
+#ifdef CONFIG_PROC_FS
+void ipipe_init_proc(void);
+
+#ifdef CONFIG_IPIPE_TRACE
+void __ipipe_init_tracer(void);
+#else /* !CONFIG_IPIPE_TRACE */
+#define __ipipe_init_tracer()       do { } while(0)
+#endif /* CONFIG_IPIPE_TRACE */
+
+#else	/* !CONFIG_PROC_FS */
+#define ipipe_init_proc()	do { } while(0)
+#endif	/* CONFIG_PROC_FS */
+
+void __ipipe_init_stage(struct ipipe_domain *ipd);
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd);
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd);
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd);
+
+void __ipipe_flush_printk(unsigned irq, void *cookie);
+
+void fastcall __ipipe_walk_pipeline(struct list_head *pos);
+
+int fastcall __ipipe_schedule_irq(unsigned irq, struct list_head *head);
+
+int fastcall __ipipe_dispatch_event(unsigned event, void *data);
+
+int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head_domain, unsigned irq);
+
+void fastcall __ipipe_sync_stage(unsigned long syncmask);
+
+void fastcall __ipipe_set_irq_pending(struct ipipe_domain *ipd, unsigned irq);
+
+void fastcall __ipipe_lock_irq(struct ipipe_domain *ipd, int cpu, unsigned irq);
+
+void fastcall __ipipe_unlock_irq(struct ipipe_domain *ipd, unsigned irq);
+
+void __ipipe_pin_range_globally(unsigned long start, unsigned long end);
+
+/* Must be called hw IRQs off. */
+static inline void ipipe_irq_lock(unsigned irq)
+{
+	__ipipe_lock_irq(ipipe_current_domain, ipipe_processor_id(), irq);
+}
+
+/* Must be called hw IRQs off. */
+static inline void ipipe_irq_unlock(unsigned irq)
+{
+	__ipipe_unlock_irq(ipipe_current_domain, irq);
+}
+
+#ifndef __ipipe_sync_pipeline
+#define __ipipe_sync_pipeline(syncmask) __ipipe_sync_stage(syncmask)
+#endif
+
+#ifndef __ipipe_run_irqtail
+#define __ipipe_run_irqtail() do { } while(0)
+#endif
+
+#define __ipipe_pipeline_head_p(ipd) (&(ipd)->p_link == __ipipe_pipeline.next)
+
+/*
+ * Keep the following as a macro, so that client code could check for
+ * the support of the invariant pipeline head optimization.
+ */
+#define __ipipe_pipeline_head() list_entry(__ipipe_pipeline.next,struct ipipe_domain,p_link)
+
+#define __ipipe_event_monitored_p(ev) \
+	(__ipipe_event_monitors[ev] > 0 || (ipipe_current_domain->evself & (1LL << ev)))
+
+#ifdef CONFIG_SMP
+
+cpumask_t __ipipe_set_irq_affinity(unsigned irq,
+				   cpumask_t cpumask);
+
+int fastcall __ipipe_send_ipi(unsigned ipi,
+			      cpumask_t cpumask);
+
+#endif /* CONFIG_SMP */
+
+#define ipipe_sigwake_notify(p)	\
+do {					\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_SIGWAKE)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_SIGWAKE,p);		\
+} while(0)
+
+#define ipipe_exit_notify(p)	\
+do {				\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_EXIT)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_EXIT,p);		\
+} while(0)
+
+#define ipipe_setsched_notify(p)	\
+do {					\
+	if (((p)->flags & PF_EVNOTIFY) && __ipipe_event_monitored_p(IPIPE_EVENT_SETSCHED)) \
+		__ipipe_dispatch_event(IPIPE_EVENT_SETSCHED,p);		\
+} while(0)
+
+#define ipipe_schedule_notify(prev, next)				\
+do {									\
+	if ((((prev)->flags|(next)->flags) & PF_EVNOTIFY) &&		\
+	    __ipipe_event_monitored_p(IPIPE_EVENT_SCHEDULE))		\
+		__ipipe_dispatch_event(IPIPE_EVENT_SCHEDULE,next);	\
+} while(0)
+
+#define ipipe_trap_notify(ex, regs)		\
+({						\
+	int ret = 0;				\
+	if ((test_bit(IPIPE_NOSTACK_FLAG, &ipipe_this_cpudom_var(status)) || \
+	     ((current)->flags & PF_EVNOTIFY)) &&			\
+	    __ipipe_event_monitored_p(ex))				\
+		ret = __ipipe_dispatch_event(ex, regs);			\
+	ret;								\
+})
+
+static inline void ipipe_init_notify(struct task_struct *p)
+{
+	if (__ipipe_event_monitored_p(IPIPE_EVENT_INIT))
+		__ipipe_dispatch_event(IPIPE_EVENT_INIT,p);
+}
+
+struct mm_struct;
+
+static inline void ipipe_cleanup_notify(struct mm_struct *mm)
+{
+	if (__ipipe_event_monitored_p(IPIPE_EVENT_CLEANUP))
+		__ipipe_dispatch_event(IPIPE_EVENT_CLEANUP,mm);
+}
+
+/* Public interface */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr);
+
+int ipipe_unregister_domain(struct ipipe_domain *ipd);
+
+void ipipe_suspend_domain(void);
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 ipipe_irq_handler_t handler,
+			 void *cookie,
+			 ipipe_irq_ackfn_t acknowledge,
+			 unsigned modemask);
+
+int ipipe_control_irq(unsigned irq,
+		      unsigned clrmask,
+		      unsigned setmask);
+
+unsigned ipipe_alloc_virq(void);
+
+int ipipe_free_virq(unsigned virq);
+
+int fastcall ipipe_trigger_irq(unsigned irq);
+
+static inline int ipipe_propagate_irq(unsigned irq)
+{
+	return __ipipe_schedule_irq(irq, ipipe_current_domain->p_link.next);
+}
+
+static inline int ipipe_schedule_irq(unsigned irq)
+{
+	return __ipipe_schedule_irq(irq, &ipipe_current_domain->p_link);
+}
+
+void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd);
+
+unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd);
+
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd);
+
+void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					  unsigned long x);
+
+static inline unsigned long ipipe_test_pipeline_from(struct ipipe_domain *ipd)
+{
+	return test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(ipd, status));
+}
+
+static inline void ipipe_stall_pipeline_head(void)
+{
+	local_irq_disable_hw();
+	__set_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(__ipipe_pipeline_head(), status));
+}
+
+static inline unsigned long ipipe_test_and_stall_pipeline_head(void)
+{
+	local_irq_disable_hw();
+	return __test_and_set_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(__ipipe_pipeline_head(), status));
+}
+
+void ipipe_unstall_pipeline_head(void);
+
+void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head_domain,
+					    unsigned long x);
+
+static inline void ipipe_restore_pipeline_head(unsigned long x)
+{
+	struct ipipe_domain *head_domain = __ipipe_pipeline_head();
+	/* On some archs, __test_and_set_bit() might return different
+	 * truth value than test_bit(), so we test the exclusive OR of
+	 * both statuses, assuming that the lowest bit is always set in
+	 * the truth value (if this is wrong, the failed optimization will
+	 * be caught in __ipipe_restore_pipeline_head() if
+	 * CONFIG_DEBUG_KERNEL is set). */
+	if ((x ^ test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status))) & 1)
+		__ipipe_restore_pipeline_head(head_domain, x);
+}
+
+#define ipipe_unstall_pipeline() \
+	ipipe_unstall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_and_unstall_pipeline() \
+	ipipe_test_and_unstall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_pipeline() \
+	ipipe_test_pipeline_from(ipipe_current_domain)
+
+#define ipipe_test_and_stall_pipeline() \
+	ipipe_test_and_stall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_stall_pipeline() \
+	ipipe_stall_pipeline_from(ipipe_current_domain)
+
+#define ipipe_restore_pipeline(x) \
+	ipipe_restore_pipeline_from(ipipe_current_domain, (x))
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr);
+
+int ipipe_get_sysinfo(struct ipipe_sysinfo *sysinfo);
+
+unsigned long ipipe_critical_enter(void (*syncfn) (void));
+
+void ipipe_critical_exit(unsigned long flags);
+
+static inline void ipipe_set_printk_sync(struct ipipe_domain *ipd)
+{
+	set_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_printk_async(struct ipipe_domain *ipd)
+{
+	clear_bit(IPIPE_SPRINTK_FLAG, &ipd->flags);
+}
+
+static inline void ipipe_set_foreign_stack(struct ipipe_domain *ipd)
+{
+	/* Must be called hw interrupts off. */
+	__set_bit(IPIPE_NOSTACK_FLAG, &ipipe_cpudom_var(ipd, status));
+}
+
+static inline void ipipe_clear_foreign_stack(struct ipipe_domain *ipd)
+{
+	/* Must be called hw interrupts off. */
+	__clear_bit(IPIPE_NOSTACK_FLAG, &ipipe_cpudom_var(ipd, status));
+}
+
+#ifndef ipipe_safe_current
+#define ipipe_safe_current()					\
+({								\
+	struct task_struct *p;					\
+	p = test_bit(IPIPE_NOSTACK_FLAG,			\
+		     &ipipe_this_cpudom_var(status)) ? &init_task : current; \
+	p; \
+})
+#endif
+
+ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd,
+					unsigned event,
+					ipipe_event_handler_t handler);
+
+cpumask_t ipipe_set_irq_affinity(unsigned irq,
+				 cpumask_t cpumask);
+
+int fastcall ipipe_send_ipi(unsigned ipi,
+			    cpumask_t cpumask);
+
+int ipipe_setscheduler_root(struct task_struct *p,
+			    int policy,
+			    int prio);
+
+int ipipe_reenter_root(struct task_struct *prev,
+		       int policy,
+		       int prio);
+
+int ipipe_alloc_ptdkey(void);
+
+int ipipe_free_ptdkey(int key);
+
+int fastcall ipipe_set_ptd(int key,
+			   void *value);
+
+void fastcall *ipipe_get_ptd(int key);
+
+int ipipe_disable_ondemand_mappings(struct task_struct *tsk);
+
+#define local_irq_enable_hw_cond()		local_irq_enable_hw()
+#define local_irq_disable_hw_cond()		local_irq_disable_hw()
+#define local_irq_save_hw_cond(flags)		local_irq_save_hw(flags)
+#define local_irq_restore_hw_cond(flags)	local_irq_restore_hw(flags)
+#define local_irq_disable_head()		ipipe_stall_pipeline_head()
+
+#define local_irq_save_full(vflags, rflags)		\
+	do {						\
+		local_irq_save(vflags);			\
+		local_irq_save_hw(rflags);		\
+	} while(0)
+
+#define local_irq_restore_full(vflags, rflags)		\
+	do {						\
+		local_irq_restore_hw(rflags);		\
+		local_irq_restore(vflags);		\
+	} while(0)
+
+static inline void local_irq_restore_nosync(unsigned long x)
+{
+	struct ipipe_percpu_domain_data *p = ipipe_root_cpudom_ptr();
+
+	if (raw_irqs_disabled_flags(x))
+		set_bit(IPIPE_STALL_FLAG, &p->status);
+	else
+		clear_bit(IPIPE_STALL_FLAG, &p->status);
+}
+
+#define ipipe_root_domain_p		(ipipe_current_domain == ipipe_root_domain)
+
+#else	/* !CONFIG_IPIPE */
+
+#define ipipe_init()			do { } while(0)
+#define ipipe_suspend_domain()		do { } while(0)
+#define ipipe_sigwake_notify(p)		do { } while(0)
+#define ipipe_setsched_notify(p)	do { } while(0)
+#define ipipe_init_notify(p)		do { } while(0)
+#define ipipe_exit_notify(p)		do { } while(0)
+#define ipipe_cleanup_notify(mm)	do { } while(0)
+#define ipipe_trap_notify(t,r)		0
+#define ipipe_init_proc()		do { } while(0)
+#define __ipipe_pin_range_globally(start, end)	do { } while(0)
+
+#define local_irq_enable_hw_cond()		do { } while(0)
+#define local_irq_disable_hw_cond()		do { } while(0)
+#define local_irq_save_hw_cond(flags)		do { (void)(flags); } while(0)
+#define local_irq_restore_hw_cond(flags)	do { } while(0)
+
+#define local_irq_save_full(vflags, rflags)	do { (void)(vflags); local_irq_save(rflags); } while(0)
+#define local_irq_restore_full(vflags, rflags)	do { (void)(vflags); local_irq_restore(rflags); } while(0)
+#define local_irq_restore_nosync(vflags)	local_irq_restore(vflags)
+
+#define ipipe_irq_lock(irq)		do { } while(0)
+#define ipipe_irq_unlock(irq)		do { } while(0)
+
+#define ipipe_root_domain_p		1
+#define ipipe_safe_current		current
+#define ipipe_processor_id()		smp_processor_id()
+
+#define local_irq_disable_head()	local_irq_disable()
+
+#endif	/* CONFIG_IPIPE */
+
+#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
+
+#include <linux/cpumask.h>
+#include <asm/system.h>
+
+static inline int ipipe_disable_context_check(int cpu)
+{
+	return xchg(&per_cpu(ipipe_percpu_context_check, cpu), 0);
+}
+
+static inline void ipipe_restore_context_check(int cpu, int old_state)
+{
+	per_cpu(ipipe_percpu_context_check, cpu) = old_state;
+}
+
+static inline void ipipe_context_check_off(void)
+{
+	int cpu;
+	for_each_online_cpu(cpu)
+		per_cpu(ipipe_percpu_context_check, cpu) = 0;
+}
+
+#else	/* !CONFIG_IPIPE_DEBUG_CONTEXT */
+
+static inline int ipipe_disable_context_check(int cpu)
+{
+	return 0;
+}
+
+static inline void ipipe_restore_context_check(int cpu, int old_state) { }
+
+static inline void ipipe_context_check_off(void) { }
+
+#endif	/* !CONFIG_IPIPE_DEBUG_CONTEXT */
+
+#endif	/* !__LINUX_IPIPE_H */
diff --git a/include/linux/ipipe_base.h b/include/linux/ipipe_base.h
new file mode 100644
index 0000000..c32cef1
--- /dev/null
+++ b/include/linux/ipipe_base.h
@@ -0,0 +1,80 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe_base.h
+ *
+ * Copyright (C) 2002-2007 Philippe Gerum.
+ *               2007 Jan Kiszka.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_IPIPE_BASE_H
+#define __LINUX_IPIPE_BASE_H
+
+#ifdef CONFIG_IPIPE
+
+#include <linux/bitops.h>
+#include <asm/ipipe_base.h>
+
+/* 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))
+
+/* Per-cpu pipeline status */
+#define IPIPE_STALL_FLAG	0	/* Stalls a pipeline stage -- guaranteed at bit #0 */
+#define IPIPE_SYNC_FLAG		1	/* The interrupt syncer is running for the domain */
+#define IPIPE_NOSTACK_FLAG	2	/* Domain currently runs on a foreign stack */
+
+#define IPIPE_STALL_MASK	(1L << IPIPE_STALL_FLAG)
+#define IPIPE_SYNC_MASK		(1L << IPIPE_SYNC_FLAG)
+
+typedef void (*ipipe_irq_handler_t)(unsigned irq,
+				    void *cookie);
+
+extern struct ipipe_domain ipipe_root;
+
+#define ipipe_root_domain (&ipipe_root)
+
+void __ipipe_unstall_root(void);
+
+void __ipipe_restore_root(unsigned long x);
+
+#define ipipe_preempt_disable(flags)	local_irq_save_hw(flags)
+#define ipipe_preempt_enable(flags)	local_irq_restore_hw(flags)
+ 
+#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
+void ipipe_check_context(struct ipipe_domain *border_ipd);
+#else /* !CONFIG_IPIPE_DEBUG_CONTEXT */
+static inline void ipipe_check_context(struct ipipe_domain *border_ipd) { }
+#endif /* !CONFIG_IPIPE_DEBUG_CONTEXT */
+
+#else /* !CONFIG_IPIPE */
+#define ipipe_preempt_disable(flags)	do { \
+						preempt_disable(); \
+						(void)(flags); \
+					} while (0)
+#define ipipe_preempt_enable(flags)	preempt_enable()
+#define ipipe_check_context(ipd)	do { } while(0)
+#endif	/* CONFIG_IPIPE */
+
+#endif	/* !__LINUX_IPIPE_BASE_H */
diff --git a/include/linux/ipipe_compat.h b/include/linux/ipipe_compat.h
new file mode 100644
index 0000000..50a245c
--- /dev/null
+++ b/include/linux/ipipe_compat.h
@@ -0,0 +1,54 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe_compat.h
+ *
+ * Copyright (C) 2007 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_COMPAT_H
+#define __LINUX_IPIPE_COMPAT_H
+
+#ifdef CONFIG_IPIPE_COMPAT
+/*
+ * OBSOLETE: defined only for backward compatibility. Will be removed
+ * in future releases, please update client code accordingly.
+ */
+
+#ifdef CONFIG_SMP
+#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)
+#else /* !CONFIG_SMP */
+#define ipipe_declare_cpuid	const int cpuid = 0
+#define ipipe_load_cpuid()	do { } while(0)
+#define ipipe_lock_cpu(flags)	local_irq_save_hw(flags)
+#define ipipe_unlock_cpu(flags)	local_irq_restore_hw(flags)
+#define ipipe_get_cpu(flags)	do { (void)(flags); } while(0)
+#define ipipe_put_cpu(flags)	do { } while(0)
+#endif /* CONFIG_SMP */
+
+#endif /* CONFIG_IPIPE_COMPAT */
+
+#endif	/* !__LINUX_IPIPE_COMPAT_H */
diff --git a/include/linux/ipipe_percpu.h b/include/linux/ipipe_percpu.h
new file mode 100644
index 0000000..e9d115e
--- /dev/null
+++ b/include/linux/ipipe_percpu.h
@@ -0,0 +1,72 @@
+/*   -*- linux-c -*-
+ *   include/linux/ipipe_percpu.h
+ *
+ *   Copyright (C) 2007 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_PERCPU_H
+#define __LINUX_IPIPE_PERCPU_H
+
+#include <asm/percpu.h>
+#include <asm/ptrace.h>
+
+struct ipipe_domain;
+
+struct ipipe_percpu_domain_data {
+	unsigned long status;	/* <= Must be first in struct. */
+	unsigned long irqpend_himask;
+	unsigned long irqpend_lomask[IPIPE_IRQ_IWORDS];
+	unsigned long irqheld_mask[IPIPE_IRQ_IWORDS];
+	unsigned long irqall[IPIPE_NR_IRQS];
+	u64 evsync;
+};
+
+#ifdef CONFIG_SMP
+#define ipipe_percpudom(ipd, var, cpu)	\
+	(per_cpu(ipipe_percpu_darray, cpu)[(ipd)->slot].var)
+#define ipipe_cpudom_var(ipd, var)	\
+	(__raw_get_cpu_var(ipipe_percpu_darray)[(ipd)->slot].var)
+#else
+DECLARE_PER_CPU(struct ipipe_percpu_domain_data *, ipipe_percpu_daddr[CONFIG_IPIPE_DOMAINS]);
+#define ipipe_percpudom(ipd, var, cpu)	\
+	(per_cpu(ipipe_percpu_daddr, cpu)[(ipd)->slot]->var)
+#define ipipe_cpudom_var(ipd, var)	\
+	(__raw_get_cpu_var(ipipe_percpu_daddr)[(ipd)->slot]->var)
+#endif
+
+DECLARE_PER_CPU(struct ipipe_percpu_domain_data, ipipe_percpu_darray[CONFIG_IPIPE_DOMAINS]);
+
+DECLARE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain);
+
+#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
+DECLARE_PER_CPU(int, ipipe_percpu_context_check);
+#endif
+
+#define ipipe_percpu(var, cpu)		per_cpu(var, cpu)
+#define ipipe_cpu_var(var)		__raw_get_cpu_var(var)
+
+#define ipipe_root_cpudom_ptr(var)	\
+	(&__raw_get_cpu_var(ipipe_percpu_darray)[0])
+
+#define ipipe_root_cpudom_var(var)	\
+	__raw_get_cpu_var(ipipe_percpu_darray)[0].var
+
+#define ipipe_this_cpudom_var(var)	\
+	ipipe_cpudom_var(ipipe_current_domain, var)
+
+#endif	/* !__LINUX_IPIPE_PERCPU_H */
diff --git a/include/linux/ipipe_trace.h b/include/linux/ipipe_trace.h
new file mode 100644
index 0000000..5d6be15
--- /dev/null
+++ b/include/linux/ipipe_trace.h
@@ -0,0 +1,65 @@
+/* -*- linux-c -*-
+ * include/linux/ipipe_trace.h
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005-2007 Jan Kiszka.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _LINUX_IPIPE_TRACE_H
+#define _LINUX_IPIPE_TRACE_H
+
+#ifdef CONFIG_IPIPE
+
+#include <linux/types.h>
+
+void ipipe_trace_begin(unsigned long v);
+void ipipe_trace_end(unsigned long v);
+void ipipe_trace_freeze(unsigned long v);
+void ipipe_trace_special(unsigned char special_id, unsigned long v);
+void ipipe_trace_pid(pid_t pid, short prio);
+
+int ipipe_trace_max_reset(void);
+int ipipe_trace_frozen_reset(void);
+
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+#define ipipe_trace_irq_entry(irq)	ipipe_trace_begin(irq)
+#define ipipe_trace_irq_exit(irq)	ipipe_trace_end(irq)
+#define ipipe_trace_irqsoff()		ipipe_trace_begin(0x80000000UL)
+#define ipipe_trace_irqson()		ipipe_trace_end(0x80000000UL)
+#else
+#define ipipe_trace_irq_entry(irq)	do { } while(0)
+#define ipipe_trace_irq_exit(irq)	do { } while(0)
+#define ipipe_trace_irqsoff()		do { } while(0)
+#define ipipe_trace_irqson()		do { } while(0)
+#endif
+
+#endif /* CONFIG_IPIPE */
+
+#ifdef CONFIG_IPIPE_TRACE_PANIC
+
+void ipipe_trace_panic_freeze(void);
+void ipipe_trace_panic_dump(void);
+
+#else /* !CONFIG_IPIPE_TRACE_PANIC */
+
+static inline void ipipe_trace_panic_freeze(void) { }
+static inline void ipipe_trace_panic_dump(void) { }
+
+#endif /* !CONFIG_IPIPE_TRACE_PANIC */
+
+#endif	/* !__LINUX_IPIPE_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 52fc405..1369b4f 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -146,6 +146,12 @@ struct irq_chip {
  * Pad this out to 32 bytes for cache and indexing reasons.
  */
 struct irq_desc {
+#ifdef CONFIG_IPIPE
+	void			fastcall (*ipipe_ack)(unsigned int irq,
+						      struct irq_desc *desc);
+	void			fastcall (*ipipe_end)(unsigned int irq,
+						      struct irq_desc *desc);
+#endif /* CONFIG_IPIPE */
 	irq_flow_handler_t	handle_irq;
 	struct irq_chip		*chip;
 	void			*handler_data;
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 63fb18d..47b0bae 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,6 +14,8 @@
 #include <linux/compiler.h>
 #include <linux/bitops.h>
 #include <linux/log2.h>
+#include <linux/marker.h>
+#include <linux/ipipe_base.h>
 #include <asm/byteorder.h>
 #include <asm/bug.h>
 
@@ -72,9 +74,12 @@ struct user;
  */
 #ifdef CONFIG_PREEMPT_VOLUNTARY
 extern int cond_resched(void);
-# define might_resched() cond_resched()
+# define might_resched() do { \
+		ipipe_check_context(ipipe_root_domain); \
+		cond_resched(); \
+	} while (0)
 #else
-# define might_resched() do { } while (0)
+# define might_resched() ipipe_check_context(ipipe_root_domain)
 #endif
 
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 6c9873f..0b1f634 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -64,4 +64,8 @@
 #define fastcall
 #endif
 
+#ifndef notrace
+#define notrace		__attribute__((no_instrument_function))
+#endif
+
 #endif
diff --git a/include/linux/ltt-core.h b/include/linux/ltt-core.h
new file mode 100644
index 0000000..933f9ab
--- /dev/null
+++ b/include/linux/ltt-core.h
@@ -0,0 +1,33 @@
+/*
+ * linux/include/linux/ltt-core.h
+ *
+ * Copyright (C) 2005,2006 Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * This contains the core definitions for the Linux Trace Toolkit.
+ */
+
+#ifndef LTT_CORE_H
+#define LTT_CORE_H
+
+#include <linux/list.h>
+
+#ifdef CONFIG_LTT
+
+/* All modifications of ltt_traces must be done by ltt-tracer.c, while holding
+ * the semaphore. Only reading of this information can be done elsewhere, with
+ * the RCU mechanism : the preemption must be disabled while reading the
+ * list. */
+struct ltt_traces {
+	struct list_head head;		/* Traces list */
+	unsigned int num_active_traces;	/* Number of active traces */
+} ____cacheline_aligned;
+
+extern struct ltt_traces ltt_traces;
+
+
+/* Keep track of traps nesting inside LTT */
+extern volatile unsigned int ltt_nesting[];
+
+#endif //CONFIG_LTT
+
+#endif //LTT_CORE_H
diff --git a/include/linux/ltt-facilities.h b/include/linux/ltt-facilities.h
new file mode 100644
index 0000000..18772c5
--- /dev/null
+++ b/include/linux/ltt-facilities.h
@@ -0,0 +1,111 @@
+/*
+ * linux/include/linux/ltt-facilities.h
+ *
+ * Copyright (C) 2005 Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * This contains the definitions for the Linux Trace Toolkit facilities.
+ *
+ * Each facility must store its facility index number (returned by the register)
+ * in an exported symbol named :
+ *
+ * ltt_facility_name_checksum
+ *
+ * Where name is the name of the facility, and checksum is the text that
+ * corresponds to the checksum of the facility in hexadecimal notation.
+ */
+
+#ifndef _LTT_FACILITIES_H
+#define _LTT_FACILITIES_H
+
+#include <linux/types.h>
+#include <asm/atomic.h>
+
+#define FACNAME_LEN 32
+
+struct user_facility_info {
+	char name[FACNAME_LEN];
+	unsigned int num_events;
+	size_t alignment;
+	u32 checksum;
+	size_t int_size;
+	size_t long_size;
+	size_t pointer_size;
+	size_t size_t_size;
+};
+
+#ifdef __KERNEL__
+
+/* Is kernel tracing enabled */
+#if defined(CONFIG_LTT)
+
+#define LTT_FAC_PER_PROCESS 16
+
+#define LTT_MAX_NUM_FACILITIES	256
+#define LTT_RESERVED_FACILITIES	1
+
+enum ltt_facility_type {
+	LTT_FACILITY_TYPE_KERNEL,
+	LTT_FACILITY_TYPE_USER
+};
+
+struct ltt_facility {
+	const char *name;
+	const unsigned int num_events;
+	u32 checksum;
+	uint8_t id;
+	const char alignment;
+};
+
+struct ltt_facility_info {
+	char name[FACNAME_LEN];
+	enum ltt_facility_type type;
+	unsigned int num_events;
+	size_t alignment;
+	u32 checksum;
+	size_t int_size;
+	size_t long_size;
+	size_t pointer_size;
+	size_t size_t_size;
+	atomic_t ref;
+};
+
+struct ltt_trace_struct;
+
+void ltt_facility_ref(uint8_t facility_id);
+
+int ltt_facility_unregister(uint8_t facility_id);
+
+int ltt_facility_register(enum ltt_facility_type type,
+		const char *name,
+		const unsigned int num_events,
+		u32 checksum,
+		size_t int_size,
+		size_t long_size,
+		size_t pointer_size,
+		size_t size_t_size,
+		size_t alignment);
+
+int ltt_facility_verify(enum ltt_facility_type type,
+		const char *name,
+		const unsigned int num_events,
+		const u32 checksum,
+		size_t int_size,
+		size_t long_size,
+		size_t pointer_size,
+		size_t size_t_size,
+		size_t alignment);
+
+unsigned int ltt_facility_kernel_register(struct ltt_facility *facility);
+
+int ltt_facility_user_access_ok(uint8_t fac_id);
+
+void ltt_facility_free_unused(void);
+
+void ltt_facility_state_dump(struct ltt_trace_struct *trace);
+
+extern int ltt_compact_facility_num_events;
+
+#endif //__KERNEL__
+
+#endif /* defined(CONFIG_LTT) */
+#endif /* _LTT_FACILITIES_H */
diff --git a/include/linux/ltt-tracer.h b/include/linux/ltt-tracer.h
new file mode 100644
index 0000000..fc9b2c2
--- /dev/null
+++ b/include/linux/ltt-tracer.h
@@ -0,0 +1,716 @@
+/*
+ * include/ltt/ltt-tracer.h
+ *
+ * Copyright (C) 2005,2006 Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * This contains the definitions for the Linux Trace Toolkit tracer.
+ */
+
+#ifndef _LTT_TRACER_H
+#define _LTT_TRACER_H
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/limits.h>
+#include <linux/list.h>
+#include <linux/cache.h>
+#include <linux/kernel.h>
+#include <linux/timex.h>
+#include <linux/wait.h>
+#include <linux/relay.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-core.h>
+#include <linux/marker.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
+#include <asm/local.h>
+#include <asm/ltt.h>
+
+/* Number of bytes to log with a read/write event */
+#define LTT_LOG_RW_SIZE			32L
+
+/* Interval (in jiffies) at which the LTT per-CPU timer fires */
+#define LTT_PERCPU_TIMER_INTERVAL	1
+
+#ifdef CONFIG_LTT_ALIGNMENT
+
+/* Calculate the offset needed to align the type */
+static inline unsigned int ltt_align(size_t align_drift,
+		 size_t size_of_type)
+{
+	size_t alignment = min(sizeof(void*), size_of_type);
+	return ((alignment - align_drift) & (alignment-1));
+}
+/* Default arch alignment */
+#define LTT_ALIGN
+
+#else
+static inline unsigned int ltt_align(size_t align_drift,
+		 size_t size_of_type)
+{
+	return 0;
+}
+
+#define LTT_ALIGN __attribute__((packed))
+
+#endif //CONFIG_LTT_ALIGNMENT
+
+/* Maximum number of callbacks per marker */
+#define LTT_NR_CALLBACKS	10
+
+struct ltt_serialize_closure;
+
+/* Serialization callback '%k' */
+typedef char *(*ltt_serialize_cb)(char *buffer, char *str,
+			struct ltt_serialize_closure *closure,
+			int align,
+			const char *fmt, va_list *args);
+
+struct ltt_serialize_closure {
+	ltt_serialize_cb *callbacks;
+	long cb_args[LTT_NR_CALLBACKS];
+	unsigned int cb_idx;
+};
+
+char *ltt_serialize_data(char *buffer, char *str,
+			struct ltt_serialize_closure *closure,
+			int align,
+			const char *fmt, va_list *args);
+
+struct ltt_probe_data {
+	const char *name;
+	const char *format;
+	unsigned int channel_index;
+	int flags;
+	int align;
+	ltt_serialize_cb callbacks[LTT_NR_CALLBACKS];
+	marker_probe_func *probe_func;
+	uint8_t fID;
+	uint8_t eID;
+};
+
+/* LTT flags
+ *
+ * LTT_FLAG_TRACE : first arg contains trace to write into.
+ * 		    (type : struct ltt_trace_struct *)
+ * LTT_FLAG_CHANNEL : following arg contains channel index to write into.
+ *                    (type : uint8_t)
+ * LTT_FLAG_COMPACT : Write to the compact channel.
+ * LTT_FLAG_COMPACT_DATA : One va args is taken to put (trucated) in the
+ *                         header. It is expected to be a u32
+ *                         and it should not be part of the format string.
+ * LTT_FLAG_FORCE : Force write in disabled traces (internal ltt use)
+ */
+
+#define LTT_FLAG_BASE		MF_NR
+#define LTT_FLAG_TRACE		(LTT_FLAG_BASE+0)	
+#define LTT_FLAG_CHANNEL	(LTT_FLAG_BASE+1)
+#define LTT_FLAG_COMPACT	(LTT_FLAG_BASE+2)
+#define LTT_FLAG_COMPACT_DATA	(LTT_FLAG_BASE+3)
+#define LTT_FLAG_FORCE		(LTT_FLAG_BASE+4)
+
+#define ltt_flag_mask(flag)	(1 << (flag))
+
+void ltt_vtrace(const struct __mark_marker_data *mdata,
+	const char *fmt, va_list args);
+void ltt_trace(const struct __mark_marker_data *mdata, const char *fmt, ...);
+
+void ltt_init_compact_facility(void);
+
+#ifdef CONFIG_LTT
+
+struct ltt_trace_struct;
+
+/* LTTng lockless logging buffer info */
+struct ltt_channel_buf_struct {
+	/* Use the relay void *start as buffer start pointer */
+	local_t offset;			/* Current offset in the buffer */
+	atomic_long_t consumed;		/* Current offset in the buffer
+					   standard atomic access (shared) */
+	atomic_long_t active_readers;	/* Active readers count
+					   standard atomic access (shared) */
+	atomic_t wakeup_readers;	/* Boolean : wakeup readers waiting ? */
+	local_t *commit_count;		/* Commit count per sub-buffer */
+	spinlock_t full_lock;		/* buffer full condition spinlock, only
+					 * for userspace tracing blocking mode
+					 * synchronisation with reader. */
+	local_t events_lost;
+	local_t corrupted_subbuffers;
+	struct timeval	current_subbuffer_start_time;
+	wait_queue_head_t write_wait;	/* Wait queue for blocking user space
+					 * writers */
+	struct work_struct wake_writers;/* Writers wake-up work struct */
+} ____cacheline_aligned;
+
+struct ltt_channel_struct {
+	char channel_name[PATH_MAX];
+	struct ltt_trace_struct	*trace;
+	struct ltt_channel_buf_struct buf[NR_CPUS];
+	int overwrite;
+	struct kref kref;
+	int compact;
+
+	void *trans_channel_data;
+
+	/*
+	 * buffer_begin - called on buffer-switch to a new sub-buffer
+	 * @buf: the channel buffer containing the new sub-buffer
+	 */
+	void (*buffer_begin) (struct rchan_buf *buf,
+			u64 tsc, unsigned int subbuf_idx);
+	/*
+	 * buffer_end - called on buffer-switch to a new sub-buffer
+	 * @buf: the channel buffer containing the previous sub-buffer
+	 */
+	void (*buffer_end) (struct rchan_buf *buf,
+			u64 tsc, unsigned int offset, unsigned int subbuf_idx);
+};
+
+struct user_dbg_data {
+	unsigned long avail_size;
+	unsigned long write;
+	unsigned long read;
+};
+
+struct ltt_trace_ops {
+	int (*create_dirs) (struct ltt_trace_struct *new_trace);
+	void (*remove_dirs) (struct ltt_trace_struct *new_trace);
+	int (*create_channel) (char *trace_name, struct ltt_trace_struct *trace,
+				struct dentry *dir, char *channel_name,
+				struct ltt_channel_struct **ltt_chan,
+				unsigned int subbuf_size,
+				unsigned int n_subbufs, int overwrite);
+	void (*wakeup_channel) (struct ltt_channel_struct *ltt_channel);
+	void (*finish_channel) (struct ltt_channel_struct *channel);
+	void (*remove_channel) (struct ltt_channel_struct *channel);
+	void *(*reserve_slot) (struct ltt_trace_struct *trace,
+				struct ltt_channel_struct *channel,
+				void **transport_data, size_t data_size,
+				size_t *slot_size, u64 *tsc);
+	void (*commit_slot) (struct ltt_channel_struct *channel,
+				void **transport_data, void *reserved,
+				size_t slot_size);
+	int (*user_blocking) (struct ltt_trace_struct *trace,
+				unsigned int index, size_t data_size,
+				struct user_dbg_data *dbg);
+	void (*user_errors) (struct ltt_trace_struct *trace,
+				unsigned int index, size_t data_size,
+				struct user_dbg_data *dbg);
+#ifdef CONFIG_HOTPLUG_CPU
+	int (*handle_cpuhp) (struct notifier_block *nb,
+				unsigned long action, void *hcpu,
+				struct ltt_trace_struct *trace);
+#endif
+};
+
+struct ltt_transport {
+	char *name;
+	struct module *owner;
+	struct list_head node;
+	struct ltt_trace_ops ops;
+};
+
+
+enum trace_mode { LTT_TRACE_NORMAL, LTT_TRACE_FLIGHT, LTT_TRACE_HYBRID };
+
+/* Per-trace information - each trace/flight recorder represented by one */
+struct ltt_trace_struct {
+	struct list_head list;
+	int active;
+	char trace_name[NAME_MAX];
+	int paused;
+	enum trace_mode mode;
+	struct ltt_transport *transport;
+	struct ltt_trace_ops *ops;
+	struct kref ltt_transport_kref;
+	u32 freq_scale;
+	u64 start_freq;
+	u64 start_tsc;
+	unsigned long long start_monotonic;
+	struct timeval		start_time;
+	struct {
+		struct dentry			*trace_root;
+		struct dentry			*control_root;
+	} dentry;
+	struct {
+		struct ltt_channel_struct	*facilities;
+		struct ltt_channel_struct	*interrupts;
+		struct ltt_channel_struct	*processes;
+		struct ltt_channel_struct	*modules;
+		struct ltt_channel_struct	*network;
+		struct ltt_channel_struct	*cpu;
+		struct ltt_channel_struct	*compact;
+	} channel;
+	struct rchan_callbacks callbacks;
+	struct kref kref; /* Each channel has a kref of the trace struct */
+} ____cacheline_aligned;
+
+enum ltt_channels { LTT_CHANNEL_FACILITIES, LTT_CHANNEL_INTERRUPTS,
+	LTT_CHANNEL_PROCESSES, LTT_CHANNEL_MODULES, LTT_CHANNEL_CPU,
+	LTT_CHANNEL_COMPACT, LTT_CHANNEL_NETWORK };
+
+/* Hardcoded event headers */
+
+/* event header for a trace with active heartbeat : 32 bits timestamps */
+
+/* headers are 8 bytes aligned : that means members are aligned on memory
+ * boundaries *if* structure starts on a 8 bytes boundary. In order to insure
+ * such alignment, a dynamic per trace alignment value must be set.
+ *
+ * Remeber that the C compiler does align each member on the boundary equivalent
+ * to their own size.
+ *
+ * As relay subbuffers are aligned on pages, we are sure that they are 8 bytes
+ * aligned, so the buffer header and trace header are aligned.
+ *
+ * Event headers are aligned depending on the trace alignment option. */
+
+struct ltt_event_header_hb {
+	uint32_t timestamp;
+	unsigned char facility_id;
+	unsigned char event_id;
+	uint16_t event_size;
+} __attribute((packed));
+
+struct ltt_event_header_nohb {
+	uint64_t timestamp;
+	unsigned char facility_id;
+	unsigned char event_id;
+	uint16_t event_size;
+} __attribute((packed));
+
+struct ltt_event_header_compact {
+	uint32_t bitfield; /* E bits for event ID, 32-E bits for timestamp */
+} __attribute((packed));
+
+struct ltt_trace_header {
+	uint32_t magic_number;
+	uint32_t arch_type;
+	uint32_t arch_variant;
+	uint32_t float_word_order;	 /* Only useful for user space traces */
+	uint8_t arch_size;
+	uint8_t major_version;
+	uint8_t minor_version;
+	uint8_t flight_recorder;
+	uint8_t has_heartbeat;
+	uint8_t has_alignment;		/* Event header alignment */
+	uint8_t tsc_lsb_truncate;	/* LSB truncate for compact channel */
+	uint8_t tscbits;		/* TSC bits kept for compact channel */
+	uint32_t freq_scale;
+	uint64_t start_freq;
+	uint64_t start_tsc;
+	uint64_t start_monotonic;
+	uint64_t start_time_sec;
+	uint64_t start_time_usec;
+} __attribute((packed));
+
+
+/* We use asm/timex.h : cpu_khz/HZ variable in here : we might have to deal
+ * specifically with CPU frequency scaling someday, so using an interpolation
+ * between the start and end of buffer values is not flexible enough. Using an
+ * immediate frequency value permits to calculate directly the times for parts
+ * of a buffer that would be before a frequency change. */
+struct ltt_block_start_header {
+	struct { 
+		uint64_t cycle_count;
+		uint64_t freq; /* khz */
+	} begin;
+	struct { 
+		uint64_t cycle_count;
+		uint64_t freq; /* khz */
+	} end;
+	uint32_t lost_size;	/* Size unused at the end of the buffer */
+	uint32_t buf_size;	/* The size of this sub-buffer */
+	struct ltt_trace_header	trace;
+} __attribute((packed));
+
+/*
+ * ltt_subbuf_header_len - called on buffer-switch to a new sub-buffer
+ *
+ * returns the client header size at the beginning of the buffer.
+ */
+static inline unsigned int ltt_subbuf_header_len(void)
+{
+	return sizeof(struct ltt_block_start_header);
+}
+
+/* Get the offset of the channel in the ltt_trace_struct */
+#define GET_CHANNEL_INDEX(chan)	\
+	(unsigned int)&((struct ltt_trace_struct*)NULL)->channel.chan
+
+static inline struct ltt_channel_struct *ltt_get_channel_from_index(
+		struct ltt_trace_struct *trace, unsigned int index)
+{
+	return *(struct ltt_channel_struct **)((void*)trace+index);
+}
+
+
+/*
+ * ltt_get_header_size
+ *
+ * Calculate alignment offset for arch size void*. This is the
+ * alignment offset of the event header.
+ *
+ * Important note :
+ * The event header must be a size multiple of the void* size. This is necessary
+ * to be able to calculate statically the alignment offset of the variable
+ * length data fields that follows. The total offset calculated here :
+ *
+ *	 Alignment of header struct on arch size
+ * + sizeof(header struct)
+ * + padding added to end of struct to align on arch size.
+ * */
+static inline unsigned char ltt_get_header_size(
+		struct ltt_channel_struct *channel,
+		void *address,
+		size_t data_size,
+		size_t *before_hdr_pad)
+{
+	unsigned int padding;
+	unsigned int header;
+	size_t after_hdr_pad;
+	
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	if (unlikely(channel->compact))
+		header = sizeof(struct ltt_event_header_compact);
+	else
+		header = sizeof(struct ltt_event_header_hb);
+#else //CONFIG_LTT_HEARTBEAT_EVENT
+	header = sizeof(struct ltt_event_header_nohb);
+#endif // CONFIG_LTT_HEARTBEAT_EVENT
+
+	/* Padding before the header. Calculated dynamically */
+	*before_hdr_pad = ltt_align((unsigned long)address, header);
+	padding = *before_hdr_pad;
+
+	/* Padding after header, considering header aligned on ltt_align.
+	 * Calculated statically if header size is known. For compact
+	 * channels, do not align the data. */
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	if (unlikely(channel->compact))
+		after_hdr_pad = 0;
+	else
+		after_hdr_pad = ltt_align(header, sizeof(void*));
+#else
+	after_hdr_pad = ltt_align(header, sizeof(void*));
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+	padding += after_hdr_pad;
+
+	return header+padding;
+}
+
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+extern int ltt_tsc_lsb_truncate;
+extern int ltt_tscbits;
+extern int ltt_compact_data_shift;
+
+static inline char *ltt_write_compact_header(struct ltt_trace_struct *trace,
+		struct ltt_channel_struct *channel,
+		void *ptr, uint8_t fID,
+		uint32_t eID, size_t event_size,
+		u64 tsc, u32 data)
+{
+	struct ltt_event_header_compact *compact_hdr;
+	int tscbits = ltt_tscbits;
+	int lsb_truncate = ltt_tsc_lsb_truncate;
+	u32 compact_tsc;
+
+	compact_hdr = (struct ltt_event_header_compact *)ptr;
+	compact_tsc = ((u32)tsc >> lsb_truncate) & ((1 << tscbits) - 1);
+	compact_hdr->bitfield = (data << ltt_compact_data_shift)
+				| (eID << tscbits) | compact_tsc;
+	return ptr + sizeof(*compact_hdr);
+}
+#else //CONFIG_LTT_HEARTBEAT_EVENT
+static inline char *ltt_write_compact_header(struct ltt_trace_struct *trace,
+		struct ltt_channel_struct *channel,
+		void *ptr, uint8_t fID,
+		uint32_t eID, size_t event_size,
+		u64 tsc, u32 data)
+{
+	return ptr;
+}
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+
+/* ltt_write_event_header
+ *
+ * Writes the event header to the pointer.
+ *
+ * @channel : pointer to the channel structure
+ * @ptr : buffer pointer
+ * @fID : facility ID
+ * @eID : event ID
+ * @event_size : size of the event, excluding the event header.
+ * @tsc : time stamp counter.
+ *
+ * returns : pointer where the event data must be written.
+ */
+static inline char *ltt_write_event_header(struct ltt_trace_struct *trace,
+		struct ltt_channel_struct *channel,
+		void *ptr, uint8_t fID,
+		uint32_t eID, size_t event_size,
+		u64 tsc)
+{
+	size_t after_hdr_pad;
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	struct ltt_event_header_hb *hb;
+
+	event_size = min(event_size, (size_t)0xFFFFU);
+	hb = (struct ltt_event_header_hb *)ptr;
+	hb->timestamp = (u32)tsc;
+	hb->facility_id = fID;
+	hb->event_id = eID;
+	hb->event_size = (uint16_t)event_size;
+	if (unlikely(channel->compact))
+		after_hdr_pad = 0;
+	else
+		after_hdr_pad = ltt_align(sizeof(*hb), sizeof(void*));
+	return ptr + sizeof(*hb) + after_hdr_pad;
+#else
+	struct ltt_event_header_nohb *nohb;
+	
+	event_size = min(event_size, (size_t)0xFFFFU);
+	nohb = (struct ltt_event_header_nohb *)ptr;
+	nohb->timestamp = (u64)tsc;
+	nohb->facility_id = fID;
+	nohb->event_id = eID;
+	nohb->event_size = (uint16_t)event_size;
+	after_hdr_pad = ltt_align(sizeof(*nohb), sizeof(void*));
+	return ptr + sizeof(*nohb) + after_hdr_pad;
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+
+}
+
+/* for flight recording. must be called after relay_commit.
+ * This function does not protect from corruption resulting from writing non
+ * sequentially in the buffer (and trying to read this buffer after a crash
+ * which occured at the wrong moment).
+ * That's why sequential writes are good!
+ *
+ * This function does nothing if trace is in normal mode. */
+#if 0
+static inline void ltt_write_commit_counter(struct rchan_buf *buf,
+		void *reserved)
+{
+	struct ltt_channel_struct *channel = 
+		(struct ltt_channel_struct*)buf->chan->client_data;
+	struct ltt_block_start_header *header =
+		(struct ltt_block_start_header*)buf->data;
+	unsigned offset, subbuf_idx;
+	
+	offset = reserved - buf->start;
+	subbuf_idx = offset / buf->chan->subbuf_size;
+
+	if (channel->trace->mode == LTT_TRACE_FLIGHT)
+		header->lost_size = buf->chan->subbuf_size - 
+			buf->commit[subbuf_idx];
+
+}
+#endif //0
+
+/* Lockless LTTng */
+
+/* Buffer offset macros */
+
+#define BUFFER_OFFSET(offset, chan) ((offset) & (chan->alloc_size-1))
+#define SUBBUF_OFFSET(offset, chan) ((offset) & (chan->subbuf_size-1))
+#define SUBBUF_ALIGN(offset, chan) \
+	(((offset) + chan->subbuf_size) & (~(chan->subbuf_size-1)))
+#define SUBBUF_TRUNC(offset, chan) \
+	((offset) & (~(chan->subbuf_size-1)))
+#define SUBBUF_INDEX(offset, chan) \
+	(BUFFER_OFFSET((offset),chan)/chan->subbuf_size)
+
+/* ltt_reserve_slot
+ *
+ * Atomic slot reservation in a LTTng buffer. It will take care of
+ * sub-buffer switching.
+ *
+ * Parameters:
+ *
+ * @trace : the trace structure to log to.
+ * @buf : the buffer to reserve space into.
+ * @data_size : size of the variable length data to log.
+ * @slot_size : pointer to total size of the slot (out)
+ * @tsc : pointer to the tsc at the slot reservation (out)
+ *
+ * Return : NULL if not enough space, else returns the pointer
+ * 					to the beginning of the reserved slot. */
+static inline void *ltt_reserve_slot(
+		struct ltt_trace_struct *trace,
+		struct ltt_channel_struct *channel,
+		void **transport_data,
+		size_t data_size,
+		size_t *slot_size,
+		u64 *tsc)
+{
+	return trace->ops->reserve_slot(trace, channel, transport_data,
+			data_size, slot_size, tsc);
+}
+	
+	
+/* ltt_commit_slot
+ *
+ * Atomic unordered slot commit. Increments the commit count in the
+ * specified sub-buffer, and delivers it if necessary.
+ *
+ * Parameters:
+ *
+ * @buf : the buffer to commit to.
+ * @reserved : address of the beginnig of the reserved slot.
+ * @slot_size : size of the reserved slot.
+ *
+ */
+static inline void ltt_commit_slot(
+		struct ltt_channel_struct *channel,
+		void **transport_data,
+		void *reserved,
+		size_t slot_size)
+{
+	struct ltt_trace_struct *trace = channel->trace;
+
+	trace->ops->commit_slot(channel, transport_data, reserved, slot_size);
+}
+
+/* 4 control channels :
+ * ltt/control/facilities
+ * ltt/control/interrupts
+ * ltt/control/processes
+ * ltt/control/network
+ *
+ * 2 cpu channels :
+ * ltt/cpu
+ * ltt/compact
+ */
+#define LTT_RELAY_ROOT		"ltt"
+#define LTT_CONTROL_ROOT	"control"
+#define LTT_FACILITIES_CHANNEL	"facilities"
+#define LTT_INTERRUPTS_CHANNEL	"interrupts"
+#define LTT_PROCESSES_CHANNEL	"processes"
+#define LTT_MODULES_CHANNEL	"modules"
+#define LTT_NETWORK_CHANNEL	"network"
+#define LTT_CPU_CHANNEL		"cpu"
+#define LTT_COMPACT_CHANNEL	"compact"
+#define LTT_FLIGHT_PREFIX	"flight-"
+
+/* System types */
+#define LTT_SYS_TYPE_VANILLA_LINUX	1
+
+/* Architecture types */
+#define LTT_ARCH_TYPE_I386		1
+#define LTT_ARCH_TYPE_PPC		2
+#define LTT_ARCH_TYPE_SH		3
+#define LTT_ARCH_TYPE_S390		4
+#define LTT_ARCH_TYPE_MIPS		5
+#define LTT_ARCH_TYPE_ARM		6
+#define LTT_ARCH_TYPE_PPC64		7
+#define LTT_ARCH_TYPE_X86_64		8
+#define LTT_ARCH_TYPE_C2		9
+#define LTT_ARCH_TYPE_POWERPC		10
+
+/* Standard definitions for variants */
+#define LTT_ARCH_VARIANT_NONE		0
+
+/* Tracer properties */
+#define LTT_DEFAULT_SUBBUF_SIZE_LOW	65536
+#define LTT_DEFAULT_N_SUBBUFS_LOW	2
+#define LTT_DEFAULT_SUBBUF_SIZE_MED	262144
+#define LTT_DEFAULT_N_SUBBUFS_MED	2
+#define LTT_DEFAULT_SUBBUF_SIZE_HIGH	1048576
+#define LTT_DEFAULT_N_SUBBUFS_HIGH	2
+#define LTT_TRACER_MAGIC_NUMBER		0x00D6B7ED
+#define LTT_TRACER_VERSION_MAJOR	0
+#define LTT_TRACER_VERSION_MINOR	8
+
+/* Size reserved for high priority events (interrupts, NMI, BH) at the end of a
+ * nearly full buffer. User space won't use this last amount of space when in
+ * blocking mode. This space also includes the event header that would be
+ * written by this user space event. */
+#define LTT_RESERVE_CRITICAL		4096
+
+/* Register and unregister function pointers */
+
+enum ltt_module_function {
+	LTT_FUNCTION_RUN_FILTER,
+	LTT_FUNCTION_FILTER_CONTROL,
+	LTT_FUNCTION_STATEDUMP
+};
+
+
+typedef int (*ltt_run_filter_functor)(struct ltt_trace_struct *trace,
+	uint8_t fID, uint8_t eID);
+
+extern ltt_run_filter_functor ltt_run_filter;
+
+extern int ltt_module_register(enum ltt_module_function name, void *function,
+		struct module *owner);
+extern void ltt_module_unregister(enum ltt_module_function name);
+
+void ltt_transport_register(struct ltt_transport *transport);
+void ltt_transport_unregister(struct ltt_transport *transport);
+
+/* Exported control function */
+
+enum ltt_heartbeat_functor_msg { LTT_HEARTBEAT_START, LTT_HEARTBEAT_STOP };
+
+enum ltt_control_msg {
+	LTT_CONTROL_START,
+	LTT_CONTROL_STOP,
+	LTT_CONTROL_CREATE_TRACE,
+	LTT_CONTROL_DESTROY_TRACE
+};
+
+union ltt_control_args {
+	struct {
+		enum trace_mode mode;
+		unsigned subbuf_size_low;
+		unsigned n_subbufs_low;
+		unsigned subbuf_size_med;
+		unsigned n_subbufs_med;
+		unsigned subbuf_size_high;
+		unsigned n_subbufs_high;
+	} new_trace;
+};
+
+extern int ltt_control(enum ltt_control_msg msg, char *trace_name,
+		char *trace_type, union ltt_control_args args);
+
+enum ltt_filter_control_msg { 
+	LTT_FILTER_DEFAULT_ACCEPT,
+	LTT_FILTER_DEFAULT_REJECT };
+
+extern int ltt_filter_control(enum ltt_filter_control_msg msg,
+		char *trace_name);
+
+void ltt_write_trace_header(struct ltt_trace_struct *trace,
+		struct ltt_trace_header *header);
+extern void ltt_buffer_destroy(struct ltt_channel_struct *ltt_chan);
+extern void ltt_wakeup_writers(struct work_struct *work);
+
+void ltt_core_register(int (*function)(u8, void*));
+
+void ltt_core_unregister(void);
+
+void ltt_release_trace(struct kref *kref);
+void ltt_release_transport(struct kref *kref);
+
+void ltt_write_full_tsc(void);
+
+#ifdef CONFIG_LTT_HEARTBEAT
+int ltt_heartbeat_trigger(enum ltt_heartbeat_functor_msg msg);
+#endif //CONFIG_LTT_HEARTBEAT
+
+/* Relay IOCTL */
+
+/* Get the next sub buffer that can be read. */
+#define RELAY_GET_SUBBUF		_IOR(0xF5, 0x00,__u32)
+/* Release the oldest reserved (by "get") sub buffer. */
+#define RELAY_PUT_SUBBUF		_IOW(0xF5, 0x01,__u32)
+/* returns the number of sub buffers in the per cpu channel. */
+#define RELAY_GET_N_SUBBUFS		_IOR(0xF5, 0x02,__u32)
+/* returns the size of the sub buffers. */
+#define RELAY_GET_SUBBUF_SIZE		_IOR(0xF5, 0x03,__u32)
+
+#endif /* CONFIG_LTT */
+
+#endif /* _LTT_TRACER_H */
diff --git a/include/linux/marker.h b/include/linux/marker.h
new file mode 100644
index 0000000..5b2714d
--- /dev/null
+++ b/include/linux/marker.h
@@ -0,0 +1,126 @@
+#ifndef _LINUX_MARKER_H
+#define _LINUX_MARKER_H
+
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing.
+ *
+ * See Documentation/marker.txt.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifdef __KERNEL__
+
+struct __mark_marker_data;
+
+typedef void marker_probe_func(const struct __mark_marker_data *mdata,
+	const char *fmt, ...);
+
+struct __mark_marker_data {
+	const char *name;
+	const char *format;
+	int flags;
+	marker_probe_func *call;
+	void *pdata;
+} __attribute__((packed));
+
+struct __mark_marker {
+	struct __mark_marker_data *mdata;
+	void *enable;
+} __attribute__((packed));
+
+#ifdef CONFIG_MARKERS
+
+/* Marker flags : selects the mechanism used to connect the probes to the
+ * markers and what can be executed within the probes. This is primarily
+ * used at reentrancy-unfriendly sites. */
+#define MF_OPTIMIZED	0	/* Use optimized markers */
+#define MF_LOCKDEP	1	/* Can call lockdep */
+#define MF_PRINTK	2	/* vprintk can be called in the probe */
+#define MF_NR		3	/* Number of marker flags */
+
+#define _MF_OPTIMIZED	(1 << MF_OPTIMIZED)
+#define _MF_LOCKDEP	(1 << MF_LOCKDEP)
+#define _MF_PRINTK	(1 << MF_PRINTK)
+
+#define DECLARE_MARKER_DATA(flags, name, format) \
+
+/* Generic marker flavor always available */
+#define MARK_GENERIC(flags, name, format, args...) \
+	do { \
+		static const char __mstrtab_name_##name[] \
+		__attribute__((section("__markers_strings"))) \
+		= #name; \
+		static const char __mstrtab_format_##name[] \
+		__attribute__((section("__markers_strings"))) \
+		= format; \
+		static struct __mark_marker_data __mark_data_##name \
+		__attribute__((section("__markers_data"))) = \
+		{ __mstrtab_name_##name,  __mstrtab_format_##name, \
+		(flags) & ~_MF_OPTIMIZED, __mark_empty_function, NULL }; \
+		static char __marker_enable_##name = 0; \
+		static const struct __mark_marker __mark_##name \
+			__attribute__((section("__markers"))) = \
+			{ &__mark_data_##name, &__marker_enable_##name } ; \
+		asm volatile ( "" : : "i" (&__mark_##name)); \
+		__mark_check_format(format, ## args); \
+		if (unlikely(__marker_enable_##name)) { \
+			unsigned long irqflags; \
+			ipipe_preempt_disable(irqflags); \
+			(*__mark_data_##name.call)(&__mark_data_##name, \
+						format, ## args); \
+			ipipe_preempt_enable(irqflags); \
+		} \
+	} while (0)
+
+#define MARK_GENERIC_ENABLE_IMMEDIATE_OFFSET 0
+#define MARK_GENERIC_ENABLE_TYPE char
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define MARK_GENERIC_ENABLE(a) \
+	*(MARK_GENERIC_ENABLE_TYPE*) \
+		((char*)a+MARK_GENERIC_ENABLE_IMMEDIATE_OFFSET)
+
+static inline int marker_generic_set_enable(void *address, char enable)
+{
+	MARK_GENERIC_ENABLE(address) = enable;
+	return 0;
+}
+
+#else /* !CONFIG_MARKERS */
+#define MARK_GENERIC(flags, name, format, args...) \
+		__mark_check_format(format, ## args)
+#endif /* CONFIG_MARKERS */
+
+#ifdef CONFIG_MARKERS_ENABLE_OPTIMIZATION
+#include <asm/marker.h>			/* optimized marker flavor */
+#else
+#include <asm-generic/marker.h>		/* fallback on generic markers */
+#endif
+
+#define MARK_MAX_FORMAT_LEN	1024
+/* Pass this as a format string for a marker with no argument */
+#define MARK_NOARGS " "
+
+/* To be used for string format validity checking with sparse */
+static inline
+void __mark_check_format(const char *fmt, ...)
+{ }
+
+extern marker_probe_func __mark_empty_function;
+
+extern int _marker_set_probe(int flags, const char *name, const char *format,
+				marker_probe_func *probe, void *pdata);
+
+#define marker_set_probe(name, format, probe, pdata) \
+	_marker_set_probe(_MF_DEFAULT, name, format, probe, pdata)
+
+extern int marker_remove_probe(const char *name);
+extern int marker_list_probe(marker_probe_func *probe);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2d2c08d..bcc8321 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -169,6 +169,7 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_MAPPED_COPY	0x01000000	/* T if mapped copy of data (nommu mmap) */
 #define VM_INSERTPAGE	0x02000000	/* The vma has had "vm_insert_page()" done on it */
 #define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
+#define VM_PINNED	0x08000000	/* Disable faults for the vma */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
diff --git a/include/linux/module.h b/include/linux/module.h
index 10f771a..b31aa24 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -356,6 +356,9 @@ struct module
 	/* The command line arguments (may be mangled).  People like
 	   keeping pointers to this stuff */
 	char *args;
+
+	const struct __mark_marker *markers;
+	unsigned int num_markers;
 };
 
 /* FIXME: It'd be nice to isolate modules during init, too, so they
@@ -469,6 +472,7 @@ extern void print_modules(void);
 struct device_driver;
 void module_add_driver(struct module *, struct device_driver *);
 void module_remove_driver(struct device_driver *);
+extern void list_modules(void);
 
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index b3b9b60..7830b4c 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -23,6 +23,7 @@
 #define NETLINK_GENERIC		16
 /* leave room for NETLINK_DM (DM Events) */
 #define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
+#define NETLINK_LTT		31 	/* Linux Trace Toolkit FIXME */
 
 #define MAX_LINKS 32		
 
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index d0926d6..991c36c 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -8,6 +8,7 @@
 
 #include <linux/thread_info.h>
 #include <linux/linkage.h>
+#include <linux/ipipe_base.h>
 
 #ifdef CONFIG_DEBUG_PREEMPT
   extern void fastcall add_preempt_count(int val);
@@ -28,18 +29,21 @@ asmlinkage void preempt_schedule(void);
 
 #define preempt_disable() \
 do { \
+	ipipe_check_context(ipipe_root_domain); \
 	inc_preempt_count(); \
 	barrier(); \
 } while (0)
 
 #define preempt_enable_no_resched() \
 do { \
+	ipipe_check_context(ipipe_root_domain); \
 	barrier(); \
 	dec_preempt_count(); \
 } while (0)
 
 #define preempt_check_resched() \
 do { \
+	ipipe_check_context(ipipe_root_domain); \
 	if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
 		preempt_schedule(); \
 } while (0)
@@ -53,10 +57,10 @@ do { \
 
 #else
 
-#define preempt_disable()		do { } while (0)
-#define preempt_enable_no_resched()	do { } while (0)
-#define preempt_enable()		do { } while (0)
-#define preempt_check_resched()		do { } while (0)
+#define preempt_disable()		ipipe_check_context(ipipe_root_domain)
+#define preempt_enable_no_resched()	ipipe_check_context(ipipe_root_domain)
+#define preempt_enable()		ipipe_check_context(ipipe_root_domain)
+#define preempt_check_resched()		ipipe_check_context(ipipe_root_domain)
 
 #endif
 
diff --git a/include/linux/relay.h b/include/linux/relay.h
index c6a48bf..759a0f9 100644
--- a/include/linux/relay.h
+++ b/include/linux/relay.h
@@ -24,7 +24,7 @@
 /*
  * Tracks changes to rchan/rchan_buf structs
  */
-#define RELAYFS_CHANNEL_VERSION		6
+#define RELAYFS_CHANNEL_VERSION		7
 
 /*
  * Per-cpu relay channel buffer
@@ -64,6 +64,10 @@ struct rchan
 	void *private_data;		/* for user-defined data */
 	size_t last_toobig;		/* tried to log event > subbuf size */
 	struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
+	int is_global;			/* One global buffer ? */
+	struct list_head list;		/* for channel list */
+	struct dentry *parent;		/* parent dentry passed to open */
+	char base_filename[NAME_MAX];	/* saved base filename */
 };
 
 /*
@@ -162,7 +166,8 @@ struct rchan *relay_open(const char *base_filename,
 			 struct dentry *parent,
 			 size_t subbuf_size,
 			 size_t n_subbufs,
-			 struct rchan_callbacks *cb);
+			 struct rchan_callbacks *cb,
+			 void *private_data);
 extern void relay_close(struct rchan *chan);
 extern void relay_flush(struct rchan *chan);
 extern void relay_subbufs_consumed(struct rchan *chan,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4463735..13b1243 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -54,6 +54,7 @@ struct sched_param {
 #include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/nodemask.h>
+#include <linux/ipipe.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -85,6 +86,7 @@ struct sched_param {
 #include <linux/task_io_accounting.h>
 
 #include <asm/processor.h>
+#include <linux/ltt-facilities.h>
 
 struct exec_domain;
 struct futex_pi_state;
@@ -151,6 +153,13 @@ extern unsigned long weighted_cpuload(const int cpu);
 /* in tsk->state again */
 #define TASK_NONINTERACTIVE	64
 #define TASK_DEAD		128
+#ifdef CONFIG_IPIPE
+#define TASK_ATOMICSWITCH	512
+#define TASK_NOWAKEUP          1024
+#else  /* !CONFIG_IPIPE */
+#define TASK_ATOMICSWITCH	0
+#define TASK_NOWAKEUP          0
+#endif /* CONFIG_IPIPE */
 
 #define __set_task_state(tsk, state_value)		\
 	do { (tsk)->state = (state_value); } while (0)
@@ -1040,6 +1049,9 @@ struct task_struct {
 
 	atomic_t fs_excl;	/* holding fs exclusive resources */
 	struct rcu_head rcu;
+#ifdef CONFIG_IPIPE
+	void *ptd[IPIPE_ROOT_NPTDKEYS];
+#endif
 
 	/*
 	 * cache last used pipe for splice
@@ -1051,6 +1063,9 @@ struct task_struct {
 #ifdef CONFIG_FAULT_INJECTION
 	int make_it_fail;
 #endif
+#ifdef CONFIG_LTT_USERSPACE_GENERIC
+	uint8_t ltt_facilities[LTT_FAC_PER_PROCESS];
+#endif //CONFIG_LTT_USERSPACE_GENERIC
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
@@ -1157,6 +1172,11 @@ static inline void put_task_struct(struct task_struct *t)
 #define PF_SPREAD_SLAB	0x02000000	/* Spread some slab caches over cpuset */
 #define PF_MEMPOLICY	0x10000000	/* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER	0x20000000	/* Thread belongs to the rt mutex tester */
+#ifdef CONFIG_IPIPE
+#define PF_EVNOTIFY    0x40000000	/* Notify other domains about internal events */
+#else
+#define PF_EVNOTIFY    0
+#endif /* CONFIG_IPIPE */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 7ba23ec..e128dcf 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -109,6 +109,8 @@ static inline int smp_call_function_single(int cpuid, void (*func) (void *info),
 
 #endif /* !SMP */
 
+#include <linux/ipipe_base.h>
+
 /*
  * smp_processor_id(): get the current CPU ID.
  *
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index 94b767d..4a254a9 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -172,7 +172,90 @@ do {								\
 #define read_trylock(lock)		__cond_lock(lock, _read_trylock(lock))
 #define write_trylock(lock)		__cond_lock(lock, _write_trylock(lock))
 
-#define spin_lock(lock)			_spin_lock(lock)
+#undef TYPE_EQUAL
+#define TYPE_EQUAL(lock, type) \
+	__builtin_types_compatible_p(typeof(lock), type *)
+
+#define PICK_SPINOP(op, lock)						\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t))			\
+		__raw_spin##op(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	else if (TYPE_EQUAL(lock, spinlock_t))				\
+		_spin##op((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINOP_RAW(op, lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t))			\
+		__raw_spin##op(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	else if (TYPE_EQUAL(lock, spinlock_t))				\
+		__raw_spin##op(&((spinlock_t *)(lock))->raw_lock);	\
+} while (0)
+
+#define PICK_SPINLOCK_IRQ(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__ipipe_spin_lock_irq(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_lock_irq((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINUNLOCK_IRQ(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__ipipe_spin_unlock_irq(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_unlock_irq((spinlock_t *)(lock));			\
+} while (0)
+
+#define PICK_SPINLOCK_IRQ_RAW(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__ipipe_spin_lock_irq(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		local_irq_disable();					\
+		__raw_spin_lock(&((spinlock_t *)(lock))->raw_lock);	\
+} while (0)
+
+#define PICK_SPINUNLOCK_IRQ_RAW(lock)					\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__ipipe_spin_unlock_irq(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		__raw_spin_unlock(&((spinlock_t *)(lock))->raw_lock);	\
+		local_irq_enable();					\
+} while (0)
+
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+extern int __bad_spinlock_type(void);
+
+#define PICK_SPINLOCK_IRQSAVE(lock, flags)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		(flags) = __ipipe_spin_lock_irqsave(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		flags = _spin_lock_irqsave((spinlock_t *)(lock));	\
+	else __bad_spinlock_type();					\
+} while (0)
+#else
+#define PICK_SPINLOCK_IRQSAVE(lock, flags)				\
+do {									\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		(flags) = __ipipe_spin_lock_irqsave(&((__ipipe_spinlock_t *)(lock))->__raw_lock); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_lock_irqsave((spinlock_t *)(lock), flags);	\
+} while (0)
+#endif
+
+#define PICK_SPINUNLOCK_IRQRESTORE(lock, flags)			\
+	do {								\
+	if (TYPE_EQUAL((lock), __ipipe_spinlock_t)) {			\
+		__ipipe_spin_unlock_irqrestore(&((__ipipe_spinlock_t *)(lock))->__raw_lock, flags); \
+	} else if (TYPE_EQUAL(lock, spinlock_t))			\
+		_spin_unlock_irqrestore((spinlock_t *)(lock), flags);	\
+} while (0)
+
+#define spin_lock(lock)	PICK_SPINOP(_lock, lock)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # define spin_lock_nested(lock, subclass) _spin_lock_nested(lock, subclass)
@@ -185,7 +268,7 @@ do {								\
 
 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
 
-#define spin_lock_irqsave(lock, flags)	flags = _spin_lock_irqsave(lock)
+#define spin_lock_irqsave(lock, flags)	PICK_SPINLOCK_IRQSAVE(lock, flags)
 #define read_lock_irqsave(lock, flags)	flags = _read_lock_irqsave(lock)
 #define write_lock_irqsave(lock, flags)	flags = _write_lock_irqsave(lock)
 
@@ -199,7 +282,7 @@ do {								\
 
 #else
 
-#define spin_lock_irqsave(lock, flags)	_spin_lock_irqsave(lock, flags)
+#define spin_lock_irqsave(lock, flags)	PICK_SPINLOCK_IRQSAVE(lock, flags)
 #define read_lock_irqsave(lock, flags)	_read_lock_irqsave(lock, flags)
 #define write_lock_irqsave(lock, flags)	_write_lock_irqsave(lock, flags)
 #define spin_lock_irqsave_nested(lock, flags, subclass)	\
@@ -207,7 +290,7 @@ do {								\
 
 #endif
 
-#define spin_lock_irq(lock)		_spin_lock_irq(lock)
+#define spin_lock_irq(lock)		PICK_SPINLOCK_IRQ(lock)
 #define spin_lock_bh(lock)		_spin_lock_bh(lock)
 
 #define read_lock_irq(lock)		_read_lock_irq(lock)
@@ -221,26 +304,25 @@ do {								\
  */
 #if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \
 	!defined(CONFIG_SMP)
-# define spin_unlock(lock)		_spin_unlock(lock)
+#define spin_unlock(lock)		PICK_SPINOP(_unlock, lock)
 # define read_unlock(lock)		_read_unlock(lock)
 # define write_unlock(lock)		_write_unlock(lock)
-# define spin_unlock_irq(lock)		_spin_unlock_irq(lock)
-# define read_unlock_irq(lock)		_read_unlock_irq(lock)
-# define write_unlock_irq(lock)		_write_unlock_irq(lock)
+# define spin_unlock_irq(lock)	PICK_SPINUNLOCK_IRQ(lock)
+# define read_unlock_irq(lock)	_read_unlock_irq(lock)
+# define write_unlock_irq(lock)	_write_unlock_irq(lock)
 #else
-# define spin_unlock(lock)		__raw_spin_unlock(&(lock)->raw_lock)
+# define spin_unlock(lock)		PICK_SPINOP_RAW(_unlock, lock)
 # define read_unlock(lock)		__raw_read_unlock(&(lock)->raw_lock)
 # define write_unlock(lock)		__raw_write_unlock(&(lock)->raw_lock)
-# define spin_unlock_irq(lock) \
-    do { __raw_spin_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
+# define spin_unlock_irq(lock)	PICK_SPINUNLOCK_IRQ_RAW(lock)
 # define read_unlock_irq(lock) \
     do { __raw_read_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
 # define write_unlock_irq(lock) \
     do { __raw_write_unlock(&(lock)->raw_lock); local_irq_enable(); } while (0)
 #endif
 
-#define spin_unlock_irqrestore(lock, flags) \
-					_spin_unlock_irqrestore(lock, flags)
+#define spin_unlock_irqrestore(lock, flags)	\
+					PICK_SPINUNLOCK_IRQRESTORE(lock, flags)
 #define spin_unlock_bh(lock)		_spin_unlock_bh(lock)
 
 #define read_unlock_irqrestore(lock, flags) \
@@ -287,4 +369,29 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
  */
 #define spin_can_lock(lock)	(!spin_is_locked(lock))
 
+#ifdef CONFIG_IPIPE
+void fastcall __ipipe_spin_lock_irq(raw_spinlock_t *lock);
+void fastcall __ipipe_spin_unlock_irq(raw_spinlock_t *lock);
+unsigned long fastcall __ipipe_spin_lock_irqsave(raw_spinlock_t *lock);
+void fastcall __ipipe_spin_unlock_irqrestore(raw_spinlock_t *lock,
+					     unsigned long x);
+void fastcall __ipipe_spin_unlock_irqbegin(ipipe_spinlock_t *lock);
+void fastcall __ipipe_spin_unlock_irqcomplete(unsigned long x);
+#define spin_lock_irqsave_cond(lock, flags) \
+	spin_lock_irqsave(lock,flags)
+#define spin_unlock_irqrestore_cond(lock, flags) \
+	spin_unlock_irqrestore(lock,flags)
+#else
+#define spin_lock_irqsave_cond(lock, flags) \
+	do { (void)(flags); spin_lock(lock); } while(0)
+#define spin_unlock_irqrestore_cond(lock, flags) \
+	spin_unlock(lock)
+#define __ipipe_spin_lock_irq(lock)		do { } while(0)
+#define __ipipe_spin_unlock_irq(lock)		do { } while(0)
+#define __ipipe_spin_lock_irqsave(lock)		0
+#define __ipipe_spin_unlock_irqrestore(lock, x)	do { (void)(x); } while(0)
+#define __ipipe_spin_unlock_irqbegin(lock)	do { } while(0)
+#define __ipipe_spin_unlock_irqcomplete(x)	do { (void)(x); } while(0)
+#endif
+
 #endif /* __LINUX_SPINLOCK_H */
diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h
index dc5fb69..28dbdc7 100644
--- a/include/linux/spinlock_types.h
+++ b/include/linux/spinlock_types.h
@@ -31,6 +31,10 @@ typedef struct {
 #endif
 } spinlock_t;
 
+typedef struct {
+	raw_spinlock_t __raw_lock;
+} __ipipe_spinlock_t;
+
 #define SPINLOCK_MAGIC		0xdead4ead
 
 typedef struct {
@@ -86,9 +90,19 @@ typedef struct {
 #endif
 
 #define SPIN_LOCK_UNLOCKED	__SPIN_LOCK_UNLOCKED(old_style_spin_init)
+#define IPIPE_SPIN_LOCK_UNLOCKED					\
+	(__ipipe_spinlock_t) {	.__raw_lock = __RAW_SPIN_LOCK_UNLOCKED }
 #define RW_LOCK_UNLOCKED	__RW_LOCK_UNLOCKED(old_style_rw_init)
 
 #define DEFINE_SPINLOCK(x)	spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
 #define DEFINE_RWLOCK(x)	rwlock_t x = __RW_LOCK_UNLOCKED(x)
 
+#ifdef CONFIG_IPIPE
+# define ipipe_spinlock_t	__ipipe_spinlock_t
+# define IPIPE_DEFINE_SPINLOCK(x) ipipe_spinlock_t x = IPIPE_SPIN_LOCK_UNLOCKED
+#else
+# define ipipe_spinlock_t	spinlock_t
+# define IPIPE_DEFINE_SPINLOCK(x) DEFINE_SPINLOCK(x)
+#endif
+
 #endif /* __LINUX_SPINLOCK_TYPES_H */
diff --git a/init/Kconfig b/init/Kconfig
index a3f83e2..da44697 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -67,6 +67,7 @@ menu "General setup"
 
 config LOCALVERSION
 	string "Local version - append to kernel release"
+	default "-ipipe"
 	help
 	  Append an extra string to the end of your kernel version.
 	  This will show up when you type uname, for example.
diff --git a/init/main.c b/init/main.c
index 8b4a7d7..6adddbb 100644
--- a/init/main.c
+++ b/init/main.c
@@ -494,7 +494,7 @@ asmlinkage void __init start_kernel(void)
 	unwind_init();
 	lockdep_init();
 
-	local_irq_disable();
+	local_irq_disable_hw();
 	early_boot_irqs_off();
 	early_init_irq_lock_class();
 
@@ -545,6 +545,11 @@ asmlinkage void __init start_kernel(void)
 	softirq_init();
 	timekeeping_init();
 	time_init();
+	/*
+	 * We need to wait for the interrupt and time subsystems to be
+	 * initialized before enabling the pipeline.
+	 */
+ 	ipipe_init();
 	profile_init();
 	if (!irqs_disabled())
 		printk("start_kernel(): bug: interrupts were enabled early\n");
@@ -691,6 +696,7 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_SYSCTL
 	sysctl_init();
 #endif
+	ipipe_init_proc();
 
 	do_initcalls();
 }
diff --git a/ipc/msg.c b/ipc/msg.c
index a388824..73890a6 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -288,6 +288,8 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
 	}
 	mutex_unlock(&msg_ids(ns).mutex);
 
+	MARK(ipc_msg_create, "%d %d", ret, msgflg);
+
 	return ret;
 }
 
diff --git a/ipc/sem.c b/ipc/sem.c
index d3e12ef..67a6caa 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -296,6 +296,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg)
 	}
 
 	mutex_unlock(&sem_ids(ns).mutex);
+	MARK(ipc_sem_create, "%d %d", err, semflg);
 	return err;
 }
 
diff --git a/ipc/shm.c b/ipc/shm.c
index f8e10a2..2cb807d 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -385,6 +385,7 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
 	}
 	mutex_unlock(&shm_ids(ns).mutex);
 
+	MARK(ipc_shm_create, "%d %d", err, shmflg);
 	return err;
 }
 
diff --git a/kernel/Kconfig.marker b/kernel/Kconfig.marker
new file mode 100644
index 0000000..fe04269
--- /dev/null
+++ b/kernel/Kconfig.marker
@@ -0,0 +1,20 @@
+# Code markers configuration
+
+config MARKERS
+	bool "Activate markers"
+	depends on MODULES
+	help
+	  Place an empty function call at each marker site. Can be
+	  dynamically changed for a probe function.
+
+config MARKERS_DISABLE_OPTIMIZATION
+	bool "Disable marker optimization"
+	depends on MARKERS && EMBEDDED
+	default n
+	help
+	  Disable code replacement jump optimisations. Especially useful if your
+	  code is in a read-only rom/flash.
+
+config MARKERS_ENABLE_OPTIMIZATION
+	def_bool y
+	depends on MARKERS && !MARKERS_DISABLE_OPTIMIZATION
diff --git a/kernel/Makefile b/kernel/Makefile
index 14f4d45..4c77db5 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_RELAY) += relay.o
+obj-$(CONFIG_IPIPE) += ipipe/
 obj-$(CONFIG_UTS_NS) += utsname.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
 obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
diff --git a/kernel/exit.c b/kernel/exit.c
index fec12eb..4fcf4c0 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -42,6 +42,7 @@
 #include <linux/audit.h> /* for audit_free() */
 #include <linux/resource.h>
 #include <linux/blkdev.h>
+#include <linux/ltt-facilities.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -62,6 +63,17 @@ static void __unhash_process(struct task_struct *p)
 
 		list_del_rcu(&p->tasks);
 		__get_cpu_var(process_counts)--;
+#ifdef CONFIG_LTT_USERSPACE_GENERIC
+		{
+			int i;
+			for (i = 0; i < LTT_FAC_PER_PROCESS; i++) {
+				if (p->ltt_facilities[i] == 0)
+					break;
+				WARN_ON(ltt_facility_unregister(
+							p->ltt_facilities[i]));
+			}
+		}
+#endif //CONFIG_LTT_USERSPACE_GENERIC
 	}
 	list_del_rcu(&p->thread_group);
 	remove_parent(p);
@@ -174,6 +186,7 @@ repeat:
 	write_unlock_irq(&tasklist_lock);
 	proc_flush_task(p);
 	release_thread(p);
+	MARK(kernel_process_free, "%d", p->pid);
 	call_rcu(&p->rcu, delayed_put_task_struct);
 
 	p = leader;
@@ -922,6 +935,8 @@ fastcall NORET_TYPE void do_exit(long code)
 
 	if (group_dead)
 		acct_process();
+	MARK(kernel_process_exit, "%d", tsk->pid);
+ 	ipipe_exit_notify(tsk);
 	exit_sem(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
@@ -1449,6 +1464,8 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
 	struct task_struct *tsk;
 	int flag, retval;
 
+	MARK(kernel_process_wait, "%d", pid);
+
 	add_wait_queue(&current->signal->wait_chldexit,&wait);
 repeat:
 	/*
diff --git a/kernel/extable.c b/kernel/extable.c
index 7fe2628..b3e856b 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -51,6 +51,7 @@ int core_kernel_text(unsigned long addr)
 		return 1;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(core_kernel_text);
 
 int __kernel_text_address(unsigned long addr)
 {
@@ -58,6 +59,7 @@ int __kernel_text_address(unsigned long addr)
 		return 1;
 	return __module_text_address(addr) != NULL;
 }
+EXPORT_SYMBOL_GPL(__kernel_text_address);
 
 int kernel_text_address(unsigned long addr)
 {
@@ -65,3 +67,4 @@ int kernel_text_address(unsigned long addr)
 		return 1;
 	return module_text_address(addr) != NULL;
 }
+EXPORT_SYMBOL_GPL(kernel_text_address);
diff --git a/kernel/fork.c b/kernel/fork.c
index d57118d..3cc2c0c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -49,6 +49,7 @@
 #include <linux/delayacct.h>
 #include <linux/taskstats_kern.h>
 #include <linux/random.h>
+#include <linux/ltt-facilities.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -68,6 +69,7 @@ int max_threads;		/* tunable limit on nr_threads */
 DEFINE_PER_CPU(unsigned long, process_counts) = 0;
 
 __cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */
+EXPORT_SYMBOL(tasklist_lock);
 
 int nr_processes(void)
 {
@@ -387,6 +389,7 @@ void mmput(struct mm_struct *mm)
 	if (atomic_dec_and_test(&mm->mm_users)) {
 		exit_aio(mm);
 		exit_mmap(mm);
+		ipipe_cleanup_notify(mm);
 		if (!list_empty(&mm->mmlist)) {
 			spin_lock(&mmlist_lock);
 			list_del(&mm->mmlist);
@@ -917,7 +920,7 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
 	unsigned long new_flags = p->flags;
 
-	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
+	new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE | PF_EVNOTIFY);
 	new_flags |= PF_FORKNOEXEC;
 	if (!(clone_flags & CLONE_PTRACE))
 		p->ptrace = 0;
@@ -1149,6 +1152,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	 * of CLONE_PTRACE.
 	 */
 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
+#ifdef CONFIG_MARKERS
+	/*
+	 * Syscall tracing must always be turned on when markers are enabled.
+	 * Use the syscall audit thread flag for now, as it is never cleared.
+	 */
+	set_tsk_thread_flag(p, TIF_SYSCALL_AUDIT);
+#endif
 #ifdef TIF_SYSCALL_EMU
 	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
 #endif
@@ -1157,6 +1167,20 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	   These must match for thread signalling to apply */
 	p->parent_exec_id = p->self_exec_id;
 
+#ifdef CONFIG_LTT_USERSPACE_GENERIC
+	if (clone_flags & CLONE_THREAD)
+		memset(p->ltt_facilities, 0, sizeof(p->ltt_facilities));
+	else {
+		int i;
+		for (i = 0; i < LTT_FAC_PER_PROCESS; i++) {
+			p->ltt_facilities[i] = current->ltt_facilities[i];
+			if (p->ltt_facilities[i] != 0)
+				ltt_facility_ref(p->ltt_facilities[i]);
+		}
+	}
+
+#endif //CONFIG_LTT_USERSPACE_GENERIC
+	
 	/* ok, now we should be set up.. */
 	p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);
 	p->pdeath_signal = 0;
@@ -1216,7 +1240,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 		spin_unlock(&current->sighand->siglock);
 		write_unlock_irq(&tasklist_lock);
 		retval = -ERESTARTNOINTR;
-		goto bad_fork_cleanup_namespaces;
+		goto bad_fork_cleanup_ltt_facilities;
 	}
 
 	if (clone_flags & CLONE_THREAD) {
@@ -1262,8 +1286,28 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	spin_unlock(&current->sighand->siglock);
 	write_unlock_irq(&tasklist_lock);
 	proc_fork_connector(p);
+#ifdef CONFIG_IPIPE
+	{
+	int k;
+
+	for (k = 0; k < IPIPE_ROOT_NPTDKEYS; k++)
+		p->ptd[k] = NULL;
+	}
+#endif /* CONFIG_IPIPE */
 	return p;
 
+bad_fork_cleanup_ltt_facilities:
+#ifdef CONFIG_LTT_USERSPACE_GENERIC
+		{
+			int i;
+			for (i = 0; i < LTT_FAC_PER_PROCESS; i++) {
+				if (p->ltt_facilities[i] == 0)
+					break;
+				WARN_ON(ltt_facility_unregister(
+							p->ltt_facilities[i]));
+			}
+		}
+#endif //CONFIG_LTT_USERSPACE_GENERIC
 bad_fork_cleanup_namespaces:
 	exit_task_namespaces(p);
 bad_fork_cleanup_keys:
@@ -1376,6 +1420,9 @@ long do_fork(unsigned long clone_flags,
 	if (!IS_ERR(p)) {
 		struct completion vfork;
 
+		MARK(kernel_process_fork, "%d %d %d",
+			current->pid, p->pid, p->tgid);
+
 		if (clone_flags & CLONE_VFORK) {
 			p->vfork_done = &vfork;
 			init_completion(&vfork);
diff --git a/kernel/ipipe/Kconfig b/kernel/ipipe/Kconfig
new file mode 100644
index 0000000..934d57c
--- /dev/null
+++ b/kernel/ipipe/Kconfig
@@ -0,0 +1,30 @@
+config IPIPE
+	bool "Interrupt pipeline"
+	default y
+	---help---
+	  Activate this option if you want the interrupt pipeline to be
+	  compiled in.
+
+config IPIPE_DOMAINS
+	int "Max domains"
+	depends on IPIPE
+	default 4
+	---help---
+	The maximum number of I-pipe domains to run concurrently.
+
+config IPIPE_COMPAT
+	bool "Maintain code compatibility with older releases"
+	depends on IPIPE
+	default y
+	---help---
+	Activate this option if you want the compatibility code to be
+	defined, so that older I-pipe clients may use obsolete
+	constructs. WARNING: obsolete code will be eventually
+	deprecated in future I-pipe releases, and removed from the
+	compatibility support as time passes. Please fix I-pipe
+	clients to get rid of such uses as soon as possible.
+
+config IPIPE_DELAYED_ATOMICSW
+       bool
+       depends on IPIPE
+       default n
diff --git a/kernel/ipipe/Kconfig.debug b/kernel/ipipe/Kconfig.debug
new file mode 100644
index 0000000..64a692c
--- /dev/null
+++ b/kernel/ipipe/Kconfig.debug
@@ -0,0 +1,88 @@
+config IPIPE_DEBUG
+	bool "I-pipe debugging"
+	depends on IPIPE
+
+config IPIPE_DEBUG_CONTEXT
+	bool "Check for illicit cross-domain calls"
+	depends on IPIPE_DEBUG
+	default y
+	---help---
+	  Enable this feature to arm checkpoints in the kernel that
+	  verify the correct invocation context. On entry of critical
+	  Linux services a warning is issued if the caller is not
+	  running over the root domain.
+
+config IPIPE_TRACE
+	bool "Latency tracing"
+	depends on IPIPE_DEBUG
+	select FRAME_POINTER
+	select KALLSYMS
+	select PROC_FS
+	---help---
+	  Activate this option if you want to use per-function tracing of
+	  the kernel. The tracer will collect data via instrumentation
+	  features like the one below or with the help of explicite calls
+	  of ipipe_trace_xxx(). See include/linux/ipipe_trace.h for the
+	  in-kernel tracing API. The collected data and runtime control
+	  is available via /proc/ipipe/trace/*.
+
+if IPIPE_TRACE
+
+config IPIPE_TRACE_ENABLE
+	bool "Enable tracing on boot"
+	default y
+	---help---
+	  Disable this option if you want to arm the tracer after booting
+	  manually ("echo 1 > /proc/ipipe/tracer/enable"). This can reduce
+	  boot time on slow embedded devices due to the tracer overhead.
+
+config IPIPE_TRACE_MCOUNT
+	bool "Instrument function entries"
+	default y
+	---help---
+	  When enabled, records every kernel function entry in the tracer
+	  log. While this slows down the system noticeably, it provides
+	  the highest level of information about the flow of events.
+	  However, it can be switch off in order to record only explicit
+	  I-pipe trace points.
+
+config IPIPE_TRACE_IRQSOFF
+	bool "Trace IRQs-off times"
+	default y
+	---help---
+	  Activate this option if I-pipe shall trace the longest path
+	  with hard-IRQs switched off.
+
+config IPIPE_TRACE_SHIFT
+	int "Depth of trace log (14 => 16Kpoints, 15 => 32Kpoints)"
+	range 10 18
+	default 14
+	---help---
+	  The number of trace points to hold tracing data for each
+	  trace path, as a power of 2.
+
+config IPIPE_TRACE_VMALLOC
+	bool "Use vmalloc'ed trace buffer"
+	default y if EMBEDDED
+	---help---
+	  Instead of reserving static kernel data, the required buffer
+	  is allocated via vmalloc during boot-up when this option is
+	  enabled. This can help to start systems that are low on memory,
+	  but it slightly degrades overall performance. Try this option
+	  when a traced kernel hangs unexpectedly at boot time.
+
+config IPIPE_TRACE_PANIC
+	bool "Enable panic back traces"
+	default y
+	---help---
+	  Provides services to freeze and dump a back trace on panic
+	  situations. This is used on IPIPE_DEBUG_CONTEXT exceptions
+	  as well as ordinary kernel oopses. You can control the number
+	  of printed back trace points via /proc/ipipe/trace.
+
+config IPIPE_TRACE_ENABLE_VALUE
+	int
+	default 0 if !IPIPE_TRACE_ENABLE
+	default 1 if IPIPE_TRACE_ENABLE
+
+endif
diff --git a/kernel/ipipe/Makefile b/kernel/ipipe/Makefile
new file mode 100644
index 0000000..6257dfa
--- /dev/null
+++ b/kernel/ipipe/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_IPIPE)	+= core.o
+obj-$(CONFIG_IPIPE_TRACE) += tracer.o
diff --git a/kernel/ipipe/core.c b/kernel/ipipe/core.c
new file mode 100644
index 0000000..186c3f6
--- /dev/null
+++ b/kernel/ipipe/core.c
@@ -0,0 +1,1536 @@
+/* -*- linux-c -*-
+ * linux/kernel/ipipe/core.c
+ *
+ * Copyright (C) 2002-2005 Philippe Gerum.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Architecture-independent I-PIPE core support.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#endif	/* CONFIG_PROC_FS */
+#include <linux/ipipe_trace.h>
+
+static int __ipipe_ptd_key_count;
+
+static unsigned long __ipipe_ptd_key_map;
+
+static unsigned long __ipipe_domain_slot_map;
+
+struct ipipe_domain ipipe_root;
+
+#ifndef CONFIG_SMP
+/*
+ * Create an alias to the unique root status, so that arch-dep code
+ * may get simple and easy access to this percpu variable.  We also
+ * create an array of pointers to the percpu domain data; this tends
+ * to produce a better code when reaching non-root domains. We make
+ * sure that the early boot code would be able to dereference the
+ * pointer to the root domain data safely by statically initializing
+ * its value (local_irq*() routines depend on this).
+ */
+#if __GNUC__ >= 4
+extern unsigned long __ipipe_root_status
+__attribute__((alias(__stringify(__raw_get_cpu_var(ipipe_percpu_darray)))));
+EXPORT_SYMBOL(__ipipe_root_status);
+#else /* __GNUC__ < 4 */
+/*
+ * Work around a GCC 3.x issue making alias symbols unusable as
+ * constant initializers.
+ */
+unsigned long *const __ipipe_root_status_addr = &__raw_get_cpu_var(ipipe_percpu_darray)[0].status;
+EXPORT_SYMBOL(__ipipe_root_status_addr);
+#endif /* __GNUC__ < 4 */
+
+DEFINE_PER_CPU(struct ipipe_percpu_domain_data *, ipipe_percpu_daddr[CONFIG_IPIPE_DOMAINS]) =
+{ [0] = (struct ipipe_percpu_domain_data *)&__raw_get_cpu_var(ipipe_percpu_darray) };
+EXPORT_PER_CPU_SYMBOL(ipipe_percpu_daddr);
+#endif /* !CONFIG_SMP */
+
+DEFINE_PER_CPU(struct ipipe_percpu_domain_data, ipipe_percpu_darray[CONFIG_IPIPE_DOMAINS]) =
+{ [0] = { .status = IPIPE_STALL_MASK } }; /* Root domain stalled on each CPU at startup. */
+
+DEFINE_PER_CPU(struct ipipe_domain *, ipipe_percpu_domain) = { &ipipe_root };
+
+static IPIPE_DEFINE_SPINLOCK(__ipipe_pipelock);
+
+LIST_HEAD(__ipipe_pipeline);
+
+unsigned long __ipipe_virtual_irq_map;
+
+#ifdef CONFIG_PRINTK
+unsigned __ipipe_printk_virq;
+#endif /* CONFIG_PRINTK */
+
+int __ipipe_event_monitors[IPIPE_NR_EVENTS];
+
+/*
+ * ipipe_init() -- Initialization routine of the IPIPE layer. Called
+ * by the host kernel early during the boot procedure.
+ */
+void ipipe_init(void)
+{
+	struct ipipe_domain *ipd = &ipipe_root;
+
+	__ipipe_check_platform();	/* Do platform dependent checks first. */
+
+	/*
+	 * A lightweight registration code for the root domain. We are
+	 * running on the boot CPU, hw interrupts are off, and
+	 * secondary CPUs are still lost in space.
+	 */
+
+	/* Reserve percpu data slot #0 for the root domain. */
+	ipd->slot = 0;
+	set_bit(0, &__ipipe_domain_slot_map);
+
+	ipd->name = "Linux";
+	ipd->domid = IPIPE_ROOT_ID;
+	ipd->priority = IPIPE_ROOT_PRIO;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+	list_add_tail(&ipd->p_link, &__ipipe_pipeline);
+
+	__ipipe_init_platform();
+
+#ifdef CONFIG_PRINTK
+	__ipipe_printk_virq = ipipe_alloc_virq();	/* Cannot fail here. */
+	ipd->irqs[__ipipe_printk_virq].handler = &__ipipe_flush_printk;
+	ipd->irqs[__ipipe_printk_virq].cookie = NULL;
+	ipd->irqs[__ipipe_printk_virq].acknowledge = NULL;
+	ipd->irqs[__ipipe_printk_virq].control = IPIPE_HANDLE_MASK;
+#endif /* CONFIG_PRINTK */
+
+	__ipipe_enable_pipeline();
+
+	printk(KERN_INFO "I-pipe %s: pipeline enabled.\n",
+	       IPIPE_VERSION_STRING);
+}
+
+void __ipipe_init_stage(struct ipipe_domain *ipd)
+{
+	int cpu, n;
+
+	for_each_online_cpu(cpu) {
+
+		ipipe_percpudom(ipd, irqpend_himask, cpu) = 0;
+
+		for (n = 0; n < IPIPE_IRQ_IWORDS; n++) {
+			ipipe_percpudom(ipd, irqpend_lomask, cpu)[n] = 0;
+			ipipe_percpudom(ipd, irqheld_mask, cpu)[n] = 0;
+		}
+
+		for (n = 0; n < IPIPE_NR_IRQS; n++)
+			ipipe_percpudom(ipd, irqall, cpu)[n] = 0;
+
+		ipipe_percpudom(ipd, evsync, cpu) = 0;
+	}
+
+	for (n = 0; n < IPIPE_NR_IRQS; n++) {
+		ipd->irqs[n].acknowledge = NULL;
+		ipd->irqs[n].handler = NULL;
+		ipd->irqs[n].control = IPIPE_PASS_MASK;	/* Pass but don't handle */
+	}
+
+	for (n = 0; n < IPIPE_NR_EVENTS; n++)
+		ipd->evhand[n] = NULL;
+
+	ipd->evself = 0LL;
+	mutex_init(&ipd->mutex);
+
+	__ipipe_hook_critical_ipi(ipd);
+}
+
+void __ipipe_cleanup_domain(struct ipipe_domain *ipd)
+{
+	ipipe_unstall_pipeline_from(ipd);
+
+#ifdef CONFIG_SMP
+	{
+		int cpu;
+
+		for_each_online_cpu(cpu) {
+			while (ipipe_percpudom(ipd, irqpend_himask, cpu) != 0)
+				cpu_relax();
+		}
+	}
+#else
+	__raw_get_cpu_var(ipipe_percpu_daddr)[ipd->slot] = NULL;
+#endif
+
+	clear_bit(ipd->slot, &__ipipe_domain_slot_map);
+}
+
+void __ipipe_unstall_root(void)
+{
+#ifndef CONFIG_IPIPE_DEBUG_CONTEXT
+	BUG_ON(!ipipe_root_domain_p);
+#endif
+
+        local_irq_disable_hw();
+
+        __clear_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+
+        if (unlikely(ipipe_root_cpudom_var(irqpend_himask) != 0))
+                __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+        local_irq_enable_hw();
+}
+
+void __ipipe_restore_root(unsigned long x)
+{
+#ifndef CONFIG_IPIPE_DEBUG_CONTEXT
+	BUG_ON(!ipipe_root_domain_p);
+#endif
+
+	if (x)
+		__ipipe_stall_root();
+	else
+		__ipipe_unstall_root();
+}
+
+void fastcall ipipe_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	set_bit_safe(IPIPE_STALL_FLAG, &ipipe_cpudom_var(ipd, status));
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+}
+
+unsigned long fastcall ipipe_test_and_stall_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long x;
+
+	x = test_and_set_bit_safe(IPIPE_STALL_FLAG, &ipipe_cpudom_var(ipd, status));
+
+	if (__ipipe_pipeline_head_p(ipd))
+		local_irq_disable_hw();
+
+	return x;
+}
+
+/*
+ * ipipe_unstall_pipeline_from() -- Unstall the pipeline and
+ * synchronize pending interrupts for a given domain. See
+ * __ipipe_walk_pipeline() for more information.
+ */
+void fastcall ipipe_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	struct list_head *pos;
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(ipd, status));
+
+	if (ipd == ipipe_current_domain)
+		pos = &ipd->p_link;
+	else
+		pos = __ipipe_pipeline.next;
+
+	__ipipe_walk_pipeline(pos);
+
+	if (likely(__ipipe_pipeline_head_p(ipd)))
+		local_irq_enable_hw();
+	else
+		local_irq_restore_hw(flags);
+}
+
+unsigned long fastcall ipipe_test_and_unstall_pipeline_from(struct ipipe_domain *ipd)
+{
+	unsigned long x;
+
+	x = test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(ipd, status));
+	ipipe_unstall_pipeline_from(ipd);
+
+	return x;
+}
+
+void fastcall ipipe_restore_pipeline_from(struct ipipe_domain *ipd,
+					  unsigned long x)
+{
+	if (x)
+		ipipe_stall_pipeline_from(ipd);
+	else
+		ipipe_unstall_pipeline_from(ipd);
+}
+
+void ipipe_unstall_pipeline_head(void)
+{
+	struct ipipe_domain *head_domain;
+
+	local_irq_disable_hw();
+
+	head_domain = __ipipe_pipeline_head();
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status));
+
+	if (unlikely(ipipe_cpudom_var(head_domain, irqpend_himask) != 0)) {
+		if (likely(head_domain == ipipe_current_domain))
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+		else
+			__ipipe_walk_pipeline(&head_domain->p_link);
+        }
+
+	local_irq_enable_hw();
+}
+
+void fastcall __ipipe_restore_pipeline_head(struct ipipe_domain *head_domain, unsigned long x)
+{
+	local_irq_disable_hw();
+
+	if (x) {
+#ifdef CONFIG_DEBUG_KERNEL
+		static int warned;
+		if (!warned && test_and_set_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status))) {
+			/*
+			 * Already stalled albeit ipipe_restore_pipeline_head()
+			 * should have detected it? Send a warning once.
+			 */
+			warned = 1;
+			printk(KERN_WARNING
+				   "I-pipe: ipipe_restore_pipeline_head() optimization failed.\n");
+			dump_stack();
+		}
+#else /* !CONFIG_DEBUG_KERNEL */
+		set_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status));
+#endif /* CONFIG_DEBUG_KERNEL */
+	}
+	else {
+		__clear_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status));
+		if (unlikely(ipipe_cpudom_var(head_domain, irqpend_himask) != 0)) {
+			if (likely(head_domain == ipipe_current_domain))
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			else
+				__ipipe_walk_pipeline(&head_domain->p_link);
+		}
+		local_irq_enable_hw();
+	}
+}
+
+void fastcall __ipipe_spin_lock_irq(raw_spinlock_t *lock)
+{
+	local_irq_disable_hw();
+	__raw_spin_lock(lock);
+	__set_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+}
+
+void fastcall __ipipe_spin_unlock_irq(raw_spinlock_t *lock)
+{
+	__raw_spin_unlock(lock);
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+	local_irq_enable_hw();
+}
+
+unsigned long fastcall __ipipe_spin_lock_irqsave(raw_spinlock_t *lock)
+{
+	unsigned long flags;
+	int s;
+
+	local_irq_save_hw(flags);
+	__raw_spin_lock(lock);
+	s = __test_and_set_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+
+	return raw_mangle_irq_bits(s, flags);
+}
+
+void fastcall __ipipe_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long x)
+{
+	__raw_spin_unlock(lock);
+	if (!raw_demangle_irq_bits(&x))
+		__clear_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+	local_irq_restore_hw(x);
+}
+
+void fastcall __ipipe_spin_unlock_irqbegin(ipipe_spinlock_t *lock)
+{
+	__raw_spin_unlock(&lock->__raw_lock);
+}
+
+void fastcall __ipipe_spin_unlock_irqcomplete(unsigned long x)
+{
+	if (!raw_demangle_irq_bits(&x))
+		__clear_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+	local_irq_restore_hw(x);
+}
+
+/* Must be called hw IRQs off. */
+void fastcall __ipipe_set_irq_pending(struct ipipe_domain *ipd, unsigned irq)
+{
+	int level = irq >> IPIPE_IRQ_ISHIFT, rank = irq & IPIPE_IRQ_IMASK;
+
+	if (likely(!test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control))) {
+		__set_bit(rank, &ipipe_cpudom_var(ipd, irqpend_lomask)[level]);
+		__set_bit(level,&ipipe_cpudom_var(ipd, irqpend_himask));
+	} else
+		__set_bit(rank, &ipipe_cpudom_var(ipd, irqheld_mask)[level]);
+
+	ipipe_cpudom_var(ipd, irqall)[irq]++;
+}
+
+/* Must be called hw IRQs off. */
+void fastcall __ipipe_lock_irq(struct ipipe_domain *ipd, int cpu, unsigned irq)
+{
+	if (likely(!test_and_set_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control))) {
+		int level = irq >> IPIPE_IRQ_ISHIFT, rank = irq & IPIPE_IRQ_IMASK;
+		if (__test_and_clear_bit(rank, &ipipe_percpudom(ipd, irqpend_lomask, cpu)[level]))
+			__set_bit(rank, &ipipe_cpudom_var(ipd, irqheld_mask)[level]);
+		if (ipipe_percpudom(ipd, irqpend_lomask, cpu)[level] == 0)
+			__clear_bit(level, &ipipe_percpudom(ipd, irqpend_himask, cpu));
+	}
+}
+
+/* Must be called hw IRQs off. */
+void fastcall __ipipe_unlock_irq(struct ipipe_domain *ipd, unsigned irq)
+{
+	int cpu;
+
+	if (likely(test_and_clear_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control))) {
+		int level = irq >> IPIPE_IRQ_ISHIFT, rank = irq & IPIPE_IRQ_IMASK;
+		for_each_online_cpu(cpu) {
+			if (test_and_clear_bit(rank, &ipipe_percpudom(ipd, irqheld_mask, cpu)[level])) {
+				/* We need atomic ops here: */
+				set_bit(rank, &ipipe_percpudom(ipd, irqpend_lomask, cpu)[level]);
+				set_bit(level, &ipipe_percpudom(ipd, irqpend_himask, cpu));
+			}
+		}
+	}
+}
+
+/* __ipipe_walk_pipeline(): Plays interrupts pending in the log. Must
+   be called with local hw interrupts disabled. */
+
+void fastcall __ipipe_walk_pipeline(struct list_head *pos)
+{
+	struct ipipe_domain *this_domain = ipipe_current_domain, *next_domain;
+
+	while (pos != &__ipipe_pipeline) {
+
+		next_domain = list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(next_domain, status)))
+			break;	/* Stalled stage -- do not go further. */
+
+		if (ipipe_cpudom_var(next_domain, irqpend_himask) != 0) {
+
+			if (next_domain == this_domain)
+				__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			else {
+
+				ipipe_cpudom_var(this_domain, evsync) = 0;
+				ipipe_current_domain = next_domain;
+				ipipe_suspend_domain();	/* Sync stage and propagate interrupts. */
+
+				if (ipipe_current_domain == next_domain)
+					ipipe_current_domain = this_domain;
+				/*
+				 * Otherwise, something changed the current domain under our
+				 * feet recycling the register set; do not override the new
+				 * domain.
+				 */
+
+				if (ipipe_cpudom_var(this_domain, irqpend_himask) != 0 &&
+				    !test_bit(IPIPE_STALL_FLAG,
+					      &ipipe_cpudom_var(this_domain, status)))
+					__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			}
+
+			break;
+		} else if (next_domain == this_domain)
+			break;
+
+		pos = next_domain->p_link.next;
+	}
+}
+
+/*
+ * ipipe_suspend_domain() -- Suspend the current domain, switching to
+ * the next one which has pending work down the pipeline.
+ */
+void ipipe_suspend_domain(void)
+{
+	struct ipipe_domain *this_domain, *next_domain;
+	struct list_head *ln;
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+	this_domain = next_domain = ipipe_current_domain;
+
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(this_domain, status));
+
+	if (ipipe_cpudom_var(this_domain, irqpend_himask) != 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,
+			     &ipipe_cpudom_var(next_domain, status)) != 0)
+			break;
+
+		if (ipipe_cpudom_var(next_domain, irqpend_himask) == 0)
+			continue;
+
+		ipipe_current_domain = next_domain;
+
+sync_stage:
+		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+		if (ipipe_current_domain != next_domain)
+			/*
+			 * Something has changed the current domain under our
+			 * feet, recycling the register set; take note.
+			 */
+			this_domain = ipipe_current_domain;
+	}
+
+	ipipe_current_domain = this_domain;
+
+	local_irq_restore_hw(flags);
+}
+
+/* ipipe_alloc_virq() -- Allocate a pipelined virtual/soft interrupt.
+ * Virtual interrupts are handled in exactly the same way than their
+ * hw-generated counterparts wrt pipelining.
+ */
+unsigned ipipe_alloc_virq(void)
+{
+	unsigned long flags, irq = 0;
+	int ipos;
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	if (__ipipe_virtual_irq_map != ~0) {
+		ipos = ffz(__ipipe_virtual_irq_map);
+		set_bit(ipos, &__ipipe_virtual_irq_map);
+		irq = ipos + IPIPE_VIRQ_BASE;
+	}
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return irq;
+}
+
+/* ipipe_virtualize_irq() -- Attach a handler (and optionally a hw
+   acknowledge routine) to an interrupt for a given domain. */
+
+int ipipe_virtualize_irq(struct ipipe_domain *ipd,
+			 unsigned irq,
+			 ipipe_irq_handler_t handler,
+			 void *cookie,
+			 ipipe_irq_ackfn_t acknowledge,
+			 unsigned modemask)
+{
+	ipipe_irq_handler_t old_handler;
+	unsigned long flags;
+	int err;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (!test_bit(IPIPE_AHEAD_FLAG, &ipd->flags))
+		/* Silently unwire interrupts for non-heading domains. */
+		modemask &= ~IPIPE_WIRED_MASK;
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	old_handler = ipd->irqs[irq].handler;
+
+	if (handler != NULL) {
+		if (handler == IPIPE_SAME_HANDLER) {
+			handler = old_handler;
+			cookie = ipd->irqs[irq].cookie;
+
+			if (handler == NULL) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+		} else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 &&
+			   old_handler != NULL) {
+			err = -EBUSY;
+			goto unlock_and_exit;
+		}
+
+		/* Wired interrupts can only be delivered to domains
+		 * always heading the pipeline, and using dynamic
+		 * propagation. */
+
+		if ((modemask & IPIPE_WIRED_MASK) != 0) {
+			if ((modemask & (IPIPE_PASS_MASK | IPIPE_STICKY_MASK)) != 0) {
+				err = -EINVAL;
+				goto unlock_and_exit;
+			}
+			modemask |= (IPIPE_HANDLE_MASK);
+		}
+
+		if ((modemask & IPIPE_STICKY_MASK) != 0)
+			modemask |= IPIPE_HANDLE_MASK;
+	} else
+		modemask &=
+		    ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK |
+		      IPIPE_EXCLUSIVE_MASK | IPIPE_WIRED_MASK);
+
+	if (acknowledge == NULL && !ipipe_virtual_irq_p(irq))
+		/*
+		 * Acknowledge handler unspecified for a hw interrupt:
+		 * use the Linux-defined handler instead.
+		 */
+		acknowledge = ipipe_root_domain->irqs[irq].acknowledge;
+
+	ipd->irqs[irq].handler = handler;
+	ipd->irqs[irq].cookie = cookie;
+	ipd->irqs[irq].acknowledge = acknowledge;
+	ipd->irqs[irq].control = modemask;
+
+	if (irq < NR_IRQS && !ipipe_virtual_irq_p(irq)) {
+		if (handler != NULL) {
+			__ipipe_enable_irqdesc(ipd, irq);
+
+			if ((modemask & IPIPE_ENABLE_MASK) != 0) {
+				if (ipd != ipipe_current_domain) {
+		/*
+		 * IRQ enable/disable state is domain-sensitive, so we
+		 * may not change it for another domain. What is
+		 * allowed however is forcing some domain to handle an
+		 * interrupt source, by passing the proper 'ipd'
+		 * descriptor which thus may be different from
+		 * __ipipe_current_domain.
+		 */
+					err = -EPERM;
+					goto unlock_and_exit;
+				}
+				__ipipe_enable_irq(irq);
+			}
+		} else if (old_handler != NULL)
+				__ipipe_disable_irqdesc(ipd, irq);
+	}
+
+	err = 0;
+
+      unlock_and_exit:
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return err;
+}
+
+/* ipipe_control_irq() -- Change modes of a pipelined interrupt for
+ * the current domain. */
+
+int ipipe_control_irq(unsigned irq, unsigned clrmask, unsigned setmask)
+{
+	struct ipipe_domain *ipd;
+	unsigned long flags;
+
+	if (irq >= IPIPE_NR_IRQS)
+		return -EINVAL;
+
+	ipd = ipipe_current_domain;
+
+	if (ipd->irqs[irq].control & IPIPE_SYSTEM_MASK)
+		return -EPERM;
+
+	if (ipd->irqs[irq].handler == NULL)
+		setmask &= ~(IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK);
+
+	if ((setmask & IPIPE_STICKY_MASK) != 0)
+		setmask |= IPIPE_HANDLE_MASK;
+
+	if ((clrmask & (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK)) != 0)	/* If one goes, both go. */
+		clrmask |= (IPIPE_HANDLE_MASK | IPIPE_STICKY_MASK);
+
+	spin_lock_irqsave(&__ipipe_pipelock, flags);
+
+	ipd->irqs[irq].control &= ~clrmask;
+	ipd->irqs[irq].control |= setmask;
+
+	if ((setmask & IPIPE_ENABLE_MASK) != 0)
+		__ipipe_enable_irq(irq);
+	else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+		__ipipe_disable_irq(irq);
+
+	spin_unlock_irqrestore(&__ipipe_pipelock, flags);
+
+	return 0;
+}
+
+/* __ipipe_dispatch_event() -- Low-level event dispatcher. */
+
+int fastcall __ipipe_dispatch_event (unsigned event, void *data)
+{
+	struct ipipe_domain *start_domain, *this_domain, *next_domain;
+	ipipe_event_handler_t evhand;
+	struct list_head *pos, *npos;
+	unsigned long flags;
+	int propagate = 1;
+
+	local_irq_save_hw(flags);
+
+	start_domain = this_domain = ipipe_current_domain;
+
+	list_for_each_safe(pos, npos, &__ipipe_pipeline) {
+		/*
+		 * Note: Domain migration may occur while running
+		 * event or interrupt handlers, in which case the
+		 * current register set is going to be recycled for a
+		 * different domain than the initiating one. We do
+		 * care for that, always tracking the current domain
+		 * descriptor upon return from those handlers.
+		 */
+		next_domain = list_entry(pos, struct ipipe_domain, p_link);
+
+		/*
+		 * Keep a cached copy of the handler's address since
+		 * ipipe_catch_event() may clear it under our feet.
+		 */
+		evhand = next_domain->evhand[event];
+
+		if (evhand != NULL) {
+			ipipe_current_domain = next_domain;
+			ipipe_cpudom_var(next_domain, evsync) |= (1LL << event);
+			local_irq_restore_hw(flags);
+			propagate = !evhand(event, start_domain, data);
+			local_irq_save_hw(flags);
+			ipipe_cpudom_var(next_domain, evsync) &= ~(1LL << event);
+			if (ipipe_current_domain != next_domain)
+				this_domain = ipipe_current_domain;
+		}
+
+		if (next_domain != ipipe_root_domain &&	/* NEVER sync the root stage here. */
+		    ipipe_cpudom_var(next_domain, irqpend_himask) != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(next_domain, status))) {
+			ipipe_current_domain = next_domain;
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+			if (ipipe_current_domain != next_domain)
+				this_domain = ipipe_current_domain;
+		}
+
+		ipipe_current_domain = this_domain;
+
+		if (next_domain == this_domain || !propagate)
+			break;
+	}
+
+	local_irq_restore_hw(flags);
+
+	return !propagate;
+}
+
+/*
+ * __ipipe_dispatch_wired -- Wired interrupt dispatcher. Wired
+ * interrupts are immediately and unconditionally delivered to the
+ * domain heading the pipeline upon receipt, and such domain must have
+ * been registered as an invariant head for the system (priority ==
+ * IPIPE_HEAD_PRIORITY). The motivation for using wired interrupts is
+ * to get an extra-fast dispatching path for those IRQs, by relying on
+ * a straightforward logic based on assumptions that must always be
+ * true for invariant head domains.  The following assumptions are
+ * made when dealing with such interrupts:
+ *
+ * 1- Wired interrupts are purely dynamic, i.e. the decision to
+ * propagate them down the pipeline must be done from the head domain
+ * ISR.
+ * 2- Wired interrupts cannot be shared or sticky.
+ * 3- The root domain cannot be an invariant pipeline head, in
+ * consequence of what the root domain cannot handle wired
+ * interrupts.
+ * 4- Wired interrupts must have a valid acknowledge handler for the
+ * head domain (if needed), and in any case, must not rely on handlers
+ * provided by lower priority domains during the acknowledge cycle
+ * (see __ipipe_handle_irq).
+ *
+ * Called with hw interrupts off.
+ */
+
+int fastcall __ipipe_dispatch_wired(struct ipipe_domain *head_domain, unsigned irq)
+{
+	struct ipipe_domain *old;
+
+	if (test_bit(IPIPE_LOCK_FLAG, &head_domain->irqs[irq].control)) {
+		/* If we can't process this IRQ right now, we must
+		 * mark it as held, so that it will get played during
+		 * normal log sync when the corresponding interrupt
+		 * source is eventually unlocked. */
+		ipipe_cpudom_var(head_domain, irqall)[irq]++;
+		__set_bit(irq & IPIPE_IRQ_IMASK, &ipipe_cpudom_var(head_domain, irqheld_mask)[irq >> IPIPE_IRQ_ISHIFT]);
+		return 0;
+	}
+
+	if (test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status))) {
+		__ipipe_set_irq_pending(head_domain, irq);
+		return 0;
+	}
+
+	old = ipipe_current_domain;
+	ipipe_current_domain = head_domain; /* Switch to the head domain. */
+
+	ipipe_cpudom_var(head_domain, irqall)[irq]++;
+	__set_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status));
+	head_domain->irqs[irq].handler(irq, head_domain->irqs[irq].cookie); /* Call the ISR. */
+	__ipipe_run_irqtail();
+	__clear_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(head_domain, status));
+
+	/* We expect the caller to start a complete pipeline walk upon
+	 * return, so that propagated interrupts will get played. */
+
+	if (ipipe_current_domain == head_domain)
+		ipipe_current_domain = old; /* Back to the preempted domain. */
+
+	return 1;
+}
+
+/*
+ * __ipipe_sync_stage() -- Flush the pending IRQs for the current
+ * domain (and processor). This routine flushes the interrupt log
+ * (see "Optimistic interrupt protection" from D. Stodolsky et al. for
+ * more on the deferred interrupt scheme). Every interrupt that
+ * occurred while the pipeline was stalled gets played. WARNING:
+ * callers on SMP boxen should always check for CPU migration on
+ * return of this routine. One can control the kind of interrupts
+ * which are going to be sync'ed using the syncmask
+ * parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT
+ * plays virtual interrupts only.
+ *
+ * This routine must be called with hw interrupts off.
+ */
+void fastcall __ipipe_sync_stage(unsigned long syncmask)
+{
+	unsigned long mask, submask;
+	struct ipipe_domain *ipd;
+	int level, rank, cpu;
+	unsigned irq;
+
+	if (__test_and_set_bit(IPIPE_SYNC_FLAG, &ipipe_this_cpudom_var(status)))
+		return;
+
+	ipd = ipipe_current_domain;
+	cpu = ipipe_processor_id();
+
+	/*
+	 * 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 = (ipipe_this_cpudom_var(irqpend_himask) & syncmask)) != 0) {
+		level = __ipipe_ffnz(mask);
+
+		while ((submask = ipipe_this_cpudom_var(irqpend_lomask)[level]) != 0) {
+			rank = __ipipe_ffnz(submask);
+			irq = (level << IPIPE_IRQ_ISHIFT) + rank;
+
+			__clear_bit(rank, &ipipe_this_cpudom_var(irqpend_lomask)[level]);
+
+			if (ipipe_this_cpudom_var(irqpend_lomask)[level] == 0)
+				__clear_bit(level, &ipipe_this_cpudom_var(irqpend_himask));
+			/*
+			 * Make sure the compiler will not postpone
+			 * the pending bitmask updates before calling
+			 * the interrupt handling routine. Otherwise,
+			 * those late updates could overwrite any
+			 * change to irqpend_hi/lomask due to a nested
+			 * interrupt, leaving the latter unprocessed
+			 * (seen on mpc836x).
+			 */
+			barrier();
+
+			if (test_bit(IPIPE_LOCK_FLAG, &ipd->irqs[irq].control))
+				continue;
+
+			__set_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+			barrier();
+
+			if (ipd == ipipe_root_domain)
+				trace_hardirqs_off();
+
+			__ipipe_run_isr(ipd, irq);
+			barrier();
+#ifdef CONFIG_SMP
+			{
+				int newcpu = ipipe_processor_id();
+
+				if (newcpu != cpu) {	/* 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.
+					 */
+					__set_bit(IPIPE_SYNC_FLAG, &ipipe_this_cpudom_var(status));
+					cpu = newcpu;
+				}
+			}
+#endif	/* CONFIG_SMP */
+			if (ipd == ipipe_root_domain &&
+			    test_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status)))
+				trace_hardirqs_on();
+
+			__clear_bit(IPIPE_STALL_FLAG, &ipipe_this_cpudom_var(status));
+		}
+	}
+
+	__clear_bit(IPIPE_SYNC_FLAG, &ipipe_this_cpudom_var(status));
+}
+
+/* ipipe_register_domain() -- Link a new domain to the pipeline. */
+
+int ipipe_register_domain(struct ipipe_domain *ipd,
+			  struct ipipe_domain_attr *attr)
+{
+	struct ipipe_domain *_ipd;
+	struct list_head *pos;
+	unsigned long flags;
+
+	if (!ipipe_root_domain_p) {
+		printk(KERN_WARNING
+		       "I-pipe: Only the root domain may register a new domain.\n");
+		return -EPERM;
+	}
+
+	if (attr->priority == IPIPE_HEAD_PRIORITY &&
+	    test_bit(IPIPE_AHEAD_FLAG,&__ipipe_pipeline_head()->flags))
+		return -EAGAIN;	/* Cannot override current head. */
+
+	flags = ipipe_critical_enter(NULL);
+
+	pos = NULL;
+	ipd->slot = ffz(__ipipe_domain_slot_map);
+
+	if (ipd->slot < CONFIG_IPIPE_DOMAINS) {
+		set_bit(ipd->slot, &__ipipe_domain_slot_map);
+		list_for_each(pos, &__ipipe_pipeline) {
+			_ipd = list_entry(pos, struct ipipe_domain, p_link);
+			if (_ipd->domid == attr->domid)
+				break;
+		}
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (pos != &__ipipe_pipeline) {
+		if (ipd->slot < CONFIG_IPIPE_DOMAINS)
+			clear_bit(ipd->slot, &__ipipe_domain_slot_map);
+		return -EBUSY;
+	}
+
+#ifndef CONFIG_SMP
+	/*
+	 * Set up the perdomain pointers for direct access to the
+	 * percpu domain data. This saves a costly multiply each time
+	 * we need to refer to the contents of the percpu domain data
+	 * array.
+	 */
+	__raw_get_cpu_var(ipipe_percpu_daddr)[ipd->slot] = &__raw_get_cpu_var(ipipe_percpu_darray)[ipd->slot];
+#endif
+
+	ipd->name = attr->name;
+	ipd->domid = attr->domid;
+	ipd->pdd = attr->pdd;
+	ipd->flags = 0;
+
+	if (attr->priority == IPIPE_HEAD_PRIORITY) {
+		ipd->priority = INT_MAX;
+		__set_bit(IPIPE_AHEAD_FLAG,&ipd->flags);
+	}
+	else
+		ipd->priority = attr->priority;
+
+	__ipipe_init_stage(ipd);
+
+	INIT_LIST_HEAD(&ipd->p_link);
+
+#ifdef CONFIG_PROC_FS
+	__ipipe_add_domain_proc(ipd);
+#endif /* CONFIG_PROC_FS */
+
+	flags = ipipe_critical_enter(NULL);
+
+	list_for_each(pos, &__ipipe_pipeline) {
+		_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_INFO "I-pipe: Domain %s registered.\n", ipd->name);
+
+	/*
+	 * Finally, allow the new domain to perform its initialization
+	 * chores.
+	 */
+
+	if (attr->entry != NULL) {
+		ipipe_current_domain = ipd;
+		attr->entry();
+		ipipe_current_domain = ipipe_root_domain;
+
+		local_irq_save_hw(flags);
+
+		if (ipipe_root_cpudom_var(irqpend_himask) != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status)))
+			__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+
+		local_irq_restore_hw(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_root_domain_p) {
+		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
+	{
+		unsigned irq;
+		int cpu;
+
+		/*
+		 * 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_each_online_cpu(cpu) {
+			while (ipipe_percpudom(ipd, irqpend_himask, cpu) > 0)
+				cpu_relax();
+		}
+	}
+#endif	/* CONFIG_SMP */
+
+	mutex_lock(&ipd->mutex);
+
+#ifdef CONFIG_PROC_FS
+	__ipipe_remove_domain_proc(ipd);
+#endif /* CONFIG_PROC_FS */
+
+	/*
+	 * Simply remove the domain from the pipeline and we are almost done.
+	 */
+
+	flags = ipipe_critical_enter(NULL);
+	list_del_init(&ipd->p_link);
+	ipipe_critical_exit(flags);
+
+	__ipipe_cleanup_domain(ipd);
+
+	mutex_unlock(&ipd->mutex);
+
+	printk(KERN_INFO "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 ipipe_domain *ipd;
+	struct list_head *ln;
+	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);
+
+	ln = head;
+
+	while (ln != &__ipipe_pipeline) {
+
+		ipd = list_entry(ln, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_HANDLE_FLAG, &ipd->irqs[irq].control)) {
+			__ipipe_set_irq_pending(ipd, irq);
+			local_irq_restore_hw(flags);
+			return 1;
+		}
+
+		ln = ipd->p_link.next;
+	}
+
+	local_irq_restore_hw(flags);
+
+	return 0;
+}
+
+/* ipipe_free_virq() -- Release a virtual/soft interrupt. */
+
+int ipipe_free_virq(unsigned virq)
+{
+	if (!ipipe_virtual_irq_p(virq))
+		return -EINVAL;
+
+	clear_bit(virq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map);
+
+	return 0;
+}
+
+void ipipe_init_attr(struct ipipe_domain_attr *attr)
+{
+	attr->name = "anon";
+	attr->domid = 1;
+	attr->entry = NULL;
+	attr->priority = IPIPE_ROOT_PRIO;
+	attr->pdd = NULL;
+}
+
+/*
+ * ipipe_catch_event() -- Interpose or remove an event handler for a
+ * given domain.
+ */
+ipipe_event_handler_t ipipe_catch_event(struct ipipe_domain *ipd,
+					unsigned event,
+					ipipe_event_handler_t handler)
+{
+	ipipe_event_handler_t old_handler;
+	unsigned long flags;
+	int self = 0, cpu;
+
+	if (event & IPIPE_EVENT_SELF) {
+		event &= ~IPIPE_EVENT_SELF;
+		self = 1;
+	}
+
+	if (event >= IPIPE_NR_EVENTS)
+		return NULL;
+
+	flags = ipipe_critical_enter(NULL);
+
+	if (!(old_handler = xchg(&ipd->evhand[event],handler)))	{
+		if (handler) {
+			if (self)
+				ipd->evself |= (1LL << event);
+			else
+				__ipipe_event_monitors[event]++;
+		}
+	}
+	else if (!handler) {
+		if (ipd->evself & (1LL << event))
+			ipd->evself &= ~(1LL << event);
+		else
+			__ipipe_event_monitors[event]--;
+	} else if ((ipd->evself & (1LL << event)) && !self) {
+			__ipipe_event_monitors[event]++;
+			ipd->evself &= ~(1LL << event);
+	} else if (!(ipd->evself & (1LL << event)) && self) {
+			__ipipe_event_monitors[event]--;
+			ipd->evself |= (1LL << event);
+	}
+
+	ipipe_critical_exit(flags);
+
+	if (!handler && ipipe_root_domain_p) {
+		/*
+		 * If we cleared a handler on behalf of the root
+		 * domain, we have to wait for any current invocation
+		 * to drain, since our caller might subsequently unmap
+		 * the target domain. To this aim, this code
+		 * synchronizes with __ipipe_dispatch_event(),
+		 * guaranteeing that either the dispatcher sees a null
+		 * handler in which case it discards the invocation
+		 * (which also prevents from entering a livelock), or
+		 * finds a valid handler and calls it. Symmetrically,
+		 * ipipe_catch_event() ensures that the called code
+		 * won't be unmapped under our feet until the event
+		 * synchronization flag is cleared for the given event
+		 * on all CPUs.
+		 */
+
+		for_each_online_cpu(cpu) {
+			while (ipipe_percpudom(ipd, evsync, cpu) & (1LL << event))
+				schedule_timeout_interruptible(HZ / 50);
+		}
+	}
+
+	return old_handler;
+}
+
+cpumask_t ipipe_set_irq_affinity (unsigned irq, cpumask_t cpumask)
+{
+#ifdef CONFIG_SMP
+	if (irq >= IPIPE_NR_XIRQS)
+		/* Allow changing affinity of external IRQs only. */
+		return CPU_MASK_NONE;
+
+	if (num_online_cpus() > 1)
+		return __ipipe_set_irq_affinity(irq,cpumask);
+#endif /* CONFIG_SMP */
+
+	return CPU_MASK_NONE;
+}
+
+int fastcall ipipe_send_ipi (unsigned ipi, cpumask_t cpumask)
+
+{
+#ifdef CONFIG_SMP
+	return __ipipe_send_ipi(ipi,cpumask);
+#else /* !CONFIG_SMP */
+	return -EINVAL;
+#endif /* CONFIG_SMP */
+}
+
+int ipipe_alloc_ptdkey (void)
+{
+	unsigned long flags;
+	int key = -1;
+
+	spin_lock_irqsave(&__ipipe_pipelock,flags);
+
+	if (__ipipe_ptd_key_count < IPIPE_ROOT_NPTDKEYS) {
+		key = ffz(__ipipe_ptd_key_map);
+		set_bit(key,&__ipipe_ptd_key_map);
+		__ipipe_ptd_key_count++;
+	}
+
+	spin_unlock_irqrestore(&__ipipe_pipelock,flags);
+
+	return key;
+}
+
+int ipipe_free_ptdkey (int key)
+{
+	unsigned long flags;
+
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&__ipipe_pipelock,flags);
+
+	if (test_and_clear_bit(key,&__ipipe_ptd_key_map))
+		__ipipe_ptd_key_count--;
+
+	spin_unlock_irqrestore(&__ipipe_pipelock,flags);
+
+	return 0;
+}
+
+int fastcall ipipe_set_ptd (int key, void *value)
+
+{
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return -EINVAL;
+
+	current->ptd[key] = value;
+
+	return 0;
+}
+
+void fastcall *ipipe_get_ptd (int key)
+
+{
+	if (key < 0 || key >= IPIPE_ROOT_NPTDKEYS)
+		return NULL;
+
+	return current->ptd[key];
+}
+
+#ifdef CONFIG_PROC_FS
+
+struct proc_dir_entry *ipipe_proc_root;
+
+static int __ipipe_version_info_proc(char *page,
+				     char **start,
+				     off_t off, int count, int *eof, void *data)
+{
+	int len = sprintf(page, "%s\n", IPIPE_VERSION_STRING);
+
+	len -= off;
+
+	if (len <= off + count)
+		*eof = 1;
+
+	*start = page + off;
+
+	if(len > count)
+		len = count;
+
+	if(len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_common_info_show(struct seq_file *p, void *data)
+{
+	struct ipipe_domain *ipd = (struct ipipe_domain *)p->private;
+	char handling, stickiness, lockbit, exclusive, virtuality;
+
+	unsigned long ctlbits;
+	unsigned irq;
+
+	seq_printf(p, "       +----- Handling ([A]ccepted, [G]rabbed, [W]ired, [D]iscarded)\n");
+	seq_printf(p, "       |+---- Sticky\n");
+	seq_printf(p, "       ||+--- Locked\n");
+	seq_printf(p, "       |||+-- Exclusive\n");
+	seq_printf(p, "       ||||+- Virtual\n");
+	seq_printf(p, "[IRQ]  |||||\n");
+
+	mutex_lock(&ipd->mutex);
+
+	for (irq = 0; irq < IPIPE_NR_IRQS; irq++) {
+		/* Remember to protect against
+		 * ipipe_virtual_irq/ipipe_control_irq if more fields
+		 * get involved. */
+		ctlbits = ipd->irqs[irq].control;
+
+		if (irq >= IPIPE_NR_XIRQS && !ipipe_virtual_irq_p(irq))
+			/*
+			 * There might be a hole between the last external
+			 * IRQ and the first virtual one; skip it.
+			 */
+			continue;
+
+		if (ipipe_virtual_irq_p(irq)
+		    && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map))
+			/* Non-allocated virtual IRQ; skip it. */
+			continue;
+
+		/*
+		 * Statuses are as follows:
+		 * o "accepted" means handled _and_ passed down the pipeline.
+		 * o "grabbed" means handled, but the interrupt might be
+		 * terminated _or_ passed down the pipeline depending on
+		 * what the domain handler asks for to the I-pipe.
+		 * o "wired" is basically the same as "grabbed", except that
+		 * the interrupt is unconditionally delivered to an invariant
+		 * pipeline head domain.
+		 * o "passed" means unhandled by the domain but passed
+		 * down the pipeline.
+		 * o "discarded" means unhandled and _not_ passed down the
+		 * pipeline. The interrupt merely disappears from the
+		 * current domain down to the end of the pipeline.
+		 */
+		if (ctlbits & IPIPE_HANDLE_MASK) {
+			if (ctlbits & IPIPE_PASS_MASK)
+				handling = 'A';
+			else if (ctlbits & IPIPE_WIRED_MASK)
+				handling = 'W';
+			else
+				handling = 'G';
+		} else if (ctlbits & IPIPE_PASS_MASK)
+			/* Do not output if no major action is taken. */
+			continue;
+		else
+			handling = 'D';
+
+		if (ctlbits & IPIPE_STICKY_MASK)
+			stickiness = 'S';
+		else
+			stickiness = '.';
+
+		if (ctlbits & IPIPE_LOCK_MASK)
+			lockbit = 'L';
+		else
+			lockbit = '.';
+
+		if (ctlbits & IPIPE_EXCLUSIVE_MASK)
+			exclusive = 'X';
+		else
+			exclusive = '.';
+
+		if (ipipe_virtual_irq_p(irq))
+			virtuality = 'V';
+		else
+			virtuality = '.';
+
+		seq_printf(p, " %3u:  %c%c%c%c%c\n",
+			     irq, handling, stickiness, lockbit, exclusive, virtuality);
+	}
+
+	seq_printf(p, "[Domain info]\n");
+
+	seq_printf(p, "id=0x%.8x\n", ipd->domid);
+
+	if (test_bit(IPIPE_AHEAD_FLAG,&ipd->flags))
+		seq_printf(p, "priority=topmost\n");
+	else
+		seq_printf(p, "priority=%d\n", ipd->priority);
+
+	mutex_unlock(&ipd->mutex);
+
+	return 0;
+}
+
+static int __ipipe_common_info_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, __ipipe_common_info_show, PROC_I(inode)->pde->data);
+}
+
+static struct file_operations __ipipe_info_proc_ops = {
+	.owner		= THIS_MODULE,
+	.open		= __ipipe_common_info_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+void __ipipe_add_domain_proc(struct ipipe_domain *ipd)
+{
+	struct proc_dir_entry *e = create_proc_entry(ipd->name, 0444, ipipe_proc_root);
+	if (e) {
+		e->proc_fops = &__ipipe_info_proc_ops;
+		e->data = (void*) ipd;
+	}
+}
+
+void __ipipe_remove_domain_proc(struct ipipe_domain *ipd)
+{
+	remove_proc_entry(ipd->name,ipipe_proc_root);
+}
+
+void __init ipipe_init_proc(void)
+{
+	ipipe_proc_root = create_proc_entry("ipipe",S_IFDIR, 0);
+	create_proc_read_entry("version",0444,ipipe_proc_root,&__ipipe_version_info_proc,NULL);
+	__ipipe_add_domain_proc(ipipe_root_domain);
+
+	__ipipe_init_tracer();
+}
+
+#endif	/* CONFIG_PROC_FS */
+
+#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
+
+DEFINE_PER_CPU(int, ipipe_percpu_context_check) = { 1 };
+
+void ipipe_check_context(struct ipipe_domain *border_ipd)
+{
+	/* Note: We don't make the per_cpu access atomic. We assume that code
+	   which temporarily disables the check does this in atomic context
+	   only. */
+	if (likely(ipipe_current_domain->priority <= border_ipd->priority) ||
+	    !per_cpu(ipipe_percpu_context_check, ipipe_processor_id()))
+		return;
+
+	ipipe_context_check_off();
+
+	ipipe_trace_panic_freeze();
+	ipipe_set_printk_sync(ipipe_current_domain);
+	printk(KERN_ERR "I-pipe: Detected illicit call from domain '%s'\n"
+	       KERN_ERR "        into a service reserved for domain '%s' and "
+			"below.\n",
+	       ipipe_current_domain->name, border_ipd->name);
+	show_stack(NULL, NULL);
+	ipipe_trace_panic_dump();
+}
+
+EXPORT_SYMBOL(ipipe_check_context);
+#endif /* CONFIG_IPIPE_DEBUG_CONTEXT */
+
+EXPORT_SYMBOL(ipipe_virtualize_irq);
+EXPORT_SYMBOL(ipipe_control_irq);
+EXPORT_SYMBOL(ipipe_suspend_domain);
+EXPORT_SYMBOL(ipipe_alloc_virq);
+EXPORT_PER_CPU_SYMBOL(ipipe_percpu_domain);
+EXPORT_PER_CPU_SYMBOL(ipipe_percpu_darray);
+EXPORT_SYMBOL(ipipe_root);
+EXPORT_SYMBOL(ipipe_stall_pipeline_from);
+EXPORT_SYMBOL(ipipe_test_and_stall_pipeline_from);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_restore_pipeline_from);
+EXPORT_SYMBOL(ipipe_test_and_unstall_pipeline_from);
+EXPORT_SYMBOL(ipipe_unstall_pipeline_head);
+EXPORT_SYMBOL(__ipipe_restore_pipeline_head);
+EXPORT_SYMBOL(__ipipe_unstall_root);
+EXPORT_SYMBOL(__ipipe_restore_root);
+EXPORT_SYMBOL(__ipipe_spin_lock_irq);
+EXPORT_SYMBOL(__ipipe_spin_unlock_irq);
+EXPORT_SYMBOL(__ipipe_spin_lock_irqsave);
+EXPORT_SYMBOL(__ipipe_spin_unlock_irqrestore);
+EXPORT_SYMBOL(__ipipe_pipeline);
+EXPORT_SYMBOL(__ipipe_lock_irq);
+EXPORT_SYMBOL(__ipipe_unlock_irq);
+EXPORT_SYMBOL(ipipe_register_domain);
+EXPORT_SYMBOL(ipipe_unregister_domain);
+EXPORT_SYMBOL(ipipe_free_virq);
+EXPORT_SYMBOL(ipipe_init_attr);
+EXPORT_SYMBOL(ipipe_catch_event);
+EXPORT_SYMBOL(ipipe_alloc_ptdkey);
+EXPORT_SYMBOL(ipipe_free_ptdkey);
+EXPORT_SYMBOL(ipipe_set_ptd);
+EXPORT_SYMBOL(ipipe_get_ptd);
+EXPORT_SYMBOL(ipipe_set_irq_affinity);
+EXPORT_SYMBOL(ipipe_send_ipi);
+EXPORT_SYMBOL(__ipipe_schedule_irq);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+EXPORT_SYMBOL(ipipe_request_tickdev);
+EXPORT_SYMBOL(ipipe_release_tickdev);
+#endif
diff --git a/kernel/ipipe/tracer.c b/kernel/ipipe/tracer.c
new file mode 100644
index 0000000..bada2c6
--- /dev/null
+++ b/kernel/ipipe/tracer.c
@@ -0,0 +1,1356 @@
+/* -*- linux-c -*-
+ * kernel/ipipe/tracer.c
+ *
+ * Copyright (C) 2005 Luotao Fu.
+ *               2005-2008 Jan Kiszka.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kallsyms.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/vmalloc.h>
+#include <linux/utsrelease.h>
+#include <linux/sched.h>
+#include <linux/ipipe.h>
+#include <asm/uaccess.h>
+
+#define IPIPE_TRACE_PATHS           4 /* <!> Do not lower below 3 */
+#define IPIPE_DEFAULT_ACTIVE        0
+#define IPIPE_DEFAULT_MAX           1
+#define IPIPE_DEFAULT_FROZEN        2
+
+#define IPIPE_TRACE_POINTS          (1 << CONFIG_IPIPE_TRACE_SHIFT)
+#define WRAP_POINT_NO(point)        ((point) & (IPIPE_TRACE_POINTS-1))
+
+#define IPIPE_DEFAULT_PRE_TRACE     10
+#define IPIPE_DEFAULT_POST_TRACE    10
+#define IPIPE_DEFAULT_BACK_TRACE    100
+
+#define IPIPE_DELAY_NOTE            1000  /* in nanoseconds */
+#define IPIPE_DELAY_WARN            10000 /* in nanoseconds */
+
+#define IPIPE_TFLG_NMI_LOCK         0x0001
+#define IPIPE_TFLG_NMI_HIT          0x0002
+#define IPIPE_TFLG_NMI_FREEZE_REQ   0x0004
+
+#define IPIPE_TFLG_HWIRQ_OFF        0x0100
+#define IPIPE_TFLG_FREEZING         0x0200
+#define IPIPE_TFLG_CURRDOM_SHIFT    10   /* bits 10..11: current domain */
+#define IPIPE_TFLG_CURRDOM_MASK     0x0C00
+#define IPIPE_TFLG_DOMSTATE_SHIFT   12   /* bits 12..15: domain stalled? */
+#define IPIPE_TFLG_DOMSTATE_BITS    3
+
+#define IPIPE_TFLG_DOMAIN_STALLED(point, n) \
+	(point->flags & (1 << (n + IPIPE_TFLG_DOMSTATE_SHIFT)))
+#define IPIPE_TFLG_CURRENT_DOMAIN(point) \
+	((point->flags & IPIPE_TFLG_CURRDOM_MASK) >> IPIPE_TFLG_CURRDOM_SHIFT)
+
+struct ipipe_trace_point {
+	short type;
+	short flags;
+	unsigned long eip;
+	unsigned long parent_eip;
+	unsigned long v;
+	unsigned long long timestamp;
+};
+
+struct ipipe_trace_path {
+	volatile int flags;
+	int dump_lock; /* separated from flags due to cross-cpu access */
+	int trace_pos; /* next point to fill */
+	int begin, end; /* finalised path begin and end */
+	int post_trace; /* non-zero when in post-trace phase */
+	unsigned long long length; /* max path length in cycles */
+	unsigned long nmi_saved_eip; /* for deferred requests from NMIs */
+	unsigned long nmi_saved_parent_eip;
+	unsigned long nmi_saved_v;
+	struct ipipe_trace_point point[IPIPE_TRACE_POINTS];
+} ____cacheline_aligned_in_smp;
+
+enum ipipe_trace_type
+{
+	IPIPE_TRACE_FUNC = 0,
+	IPIPE_TRACE_BEGIN,
+	IPIPE_TRACE_END,
+	IPIPE_TRACE_FREEZE,
+	IPIPE_TRACE_SPECIAL,
+	IPIPE_TRACE_PID,
+};
+
+#define IPIPE_TYPE_MASK             0x0007
+#define IPIPE_TYPE_BITS             3
+
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+static DEFINE_PER_CPU(struct ipipe_trace_path *, trace_path);
+#else /* !CONFIG_IPIPE_TRACE_VMALLOC */
+static DEFINE_PER_CPU(struct ipipe_trace_path, trace_path[IPIPE_TRACE_PATHS]) =
+	{ [0 ... IPIPE_TRACE_PATHS-1] = { .begin = -1, .end = -1 } };
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+
+int ipipe_trace_enable = 0;
+
+static DEFINE_PER_CPU(int, active_path) = { IPIPE_DEFAULT_ACTIVE };
+static DEFINE_PER_CPU(int, max_path) = { IPIPE_DEFAULT_MAX };
+static DEFINE_PER_CPU(int, frozen_path) = { IPIPE_DEFAULT_FROZEN };
+static IPIPE_DEFINE_SPINLOCK(global_path_lock);
+static int pre_trace = IPIPE_DEFAULT_PRE_TRACE;
+static int post_trace = IPIPE_DEFAULT_POST_TRACE;
+static int back_trace = IPIPE_DEFAULT_BACK_TRACE;
+static int verbose_trace = 1;
+static unsigned long trace_overhead;
+
+static unsigned long trigger_begin;
+static unsigned long trigger_end;
+
+static DEFINE_MUTEX(out_mutex);
+static struct ipipe_trace_path *print_path;
+#ifdef CONFIG_IPIPE_TRACE_PANIC
+static struct ipipe_trace_path *panic_path;
+#endif /* CONFIG_IPIPE_TRACE_PANIC */
+static int print_pre_trace;
+static int print_post_trace;
+
+
+static long __ipipe_signed_tsc2us(long long tsc);
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point);
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip);
+
+
+static notrace void
+__ipipe_store_domain_states(struct ipipe_trace_point *point)
+{
+	struct ipipe_domain *ipd;
+	struct list_head *pos;
+	int i = 0;
+
+	list_for_each_prev(pos, &__ipipe_pipeline) {
+		ipd = list_entry(pos, struct ipipe_domain, p_link);
+
+		if (test_bit(IPIPE_STALL_FLAG, &ipipe_cpudom_var(ipd, status)))
+			point->flags |= 1 << (i + IPIPE_TFLG_DOMSTATE_SHIFT);
+
+		if (ipd == ipipe_current_domain)
+			point->flags |= i << IPIPE_TFLG_CURRDOM_SHIFT;
+
+		if (++i > IPIPE_TFLG_DOMSTATE_BITS)
+			break;
+	}
+}
+
+static notrace int __ipipe_get_free_trace_path(int old, int cpu)
+{
+	int new_active = old;
+	struct ipipe_trace_path *tp;
+
+	do {
+		if (++new_active == IPIPE_TRACE_PATHS)
+			new_active = 0;
+		tp = &per_cpu(trace_path, cpu)[new_active];
+	} while (new_active == per_cpu(max_path, cpu) ||
+	         new_active == per_cpu(frozen_path, cpu) ||
+	         tp->dump_lock);
+
+	return new_active;
+}
+
+static notrace void
+__ipipe_migrate_pre_trace(struct ipipe_trace_path *new_tp,
+                          struct ipipe_trace_path *old_tp, int old_pos)
+{
+	int i;
+
+	new_tp->trace_pos = pre_trace+1;
+
+	for (i = new_tp->trace_pos; i > 0; i--)
+		memcpy(&new_tp->point[WRAP_POINT_NO(new_tp->trace_pos-i)],
+		       &old_tp->point[WRAP_POINT_NO(old_pos-i)],
+		       sizeof(struct ipipe_trace_point));
+
+	/* mark the end (i.e. the point before point[0]) invalid */
+	new_tp->point[IPIPE_TRACE_POINTS-1].eip = 0;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_end(int cpu, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = per_cpu(active_path, cpu);
+	unsigned long long length;
+
+	/* do we have a new worst case? */
+	length = tp->point[tp->end].timestamp -
+	         tp->point[tp->begin].timestamp;
+	if (length > per_cpu(trace_path, cpu)[per_cpu(max_path, cpu)].length) {
+		/* we need protection here against other cpus trying
+		   to start a proc dump */
+		spin_lock(&global_path_lock);
+
+		/* active path holds new worst case */
+		tp->length = length;
+		per_cpu(max_path, cpu) = active;
+
+		/* find next unused trace path */
+		active = __ipipe_get_free_trace_path(active, cpu);
+
+		spin_unlock(&global_path_lock);
+
+		tp = &per_cpu(trace_path, cpu)[active];
+
+		/* migrate last entries for pre-tracing */
+		__ipipe_migrate_pre_trace(tp, old_tp, pos);
+	}
+
+	return tp;
+}
+
+static notrace struct ipipe_trace_path *
+__ipipe_trace_freeze(int cpu, struct ipipe_trace_path *tp, int pos)
+{
+	struct ipipe_trace_path *old_tp = tp;
+	long active = per_cpu(active_path, cpu);
+	int n;
+
+	/* frozen paths have no core (begin=end) */
+	tp->begin = tp->end;
+
+	/* we need protection here against other cpus trying
+	 * to set their frozen path or to start a proc dump */
+	spin_lock(&global_path_lock);
+
+	per_cpu(frozen_path, cpu) = active;
+
+	/* find next unused trace path */
+	active = __ipipe_get_free_trace_path(active, cpu);
+
+	/* check if this is the first frozen path */
+	for_each_possible_cpu(n) {
+		if (n != cpu &&
+		    per_cpu(trace_path, n)[per_cpu(frozen_path, n)].end >= 0)
+			tp->end = -1;
+	}
+
+	spin_unlock(&global_path_lock);
+
+	tp = &per_cpu(trace_path, cpu)[active];
+
+	/* migrate last entries for pre-tracing */
+	__ipipe_migrate_pre_trace(tp, old_tp, pos);
+
+	return tp;
+}
+
+void notrace
+__ipipe_trace(enum ipipe_trace_type type, unsigned long eip,
+              unsigned long parent_eip, unsigned long v)
+{
+	struct ipipe_trace_path *tp, *old_tp;
+	int pos, next_pos, begin;
+	struct ipipe_trace_point *point;
+	unsigned long flags;
+	int cpu;
+
+	local_irq_save_hw_notrace(flags);
+
+	cpu = ipipe_processor_id();
+ restart:
+	tp = old_tp = &per_cpu(trace_path, cpu)[per_cpu(active_path, cpu)];
+
+	/* here starts a race window with NMIs - catched below */
+
+	/* check for NMI recursion */
+	if (unlikely(tp->flags & IPIPE_TFLG_NMI_LOCK)) {
+		tp->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* first freeze request from NMI context? */
+		if ((type == IPIPE_TRACE_FREEZE) &&
+		    !(tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)) {
+			/* save arguments and mark deferred freezing */
+			tp->flags |= IPIPE_TFLG_NMI_FREEZE_REQ;
+			tp->nmi_saved_eip = eip;
+			tp->nmi_saved_parent_eip = parent_eip;
+			tp->nmi_saved_v = v;
+		}
+		return; /* no need for restoring flags inside IRQ */
+	}
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (unlikely(tp !=
+		     &per_cpu(trace_path, cpu)[per_cpu(active_path, cpu)])) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	/* get the point buffer */
+	pos = tp->trace_pos;
+	point = &tp->point[pos];
+
+	/* store all trace point data */
+	point->type = type;
+	point->flags = raw_irqs_disabled_flags(flags) ? IPIPE_TFLG_HWIRQ_OFF : 0;
+	point->eip = eip;
+	point->parent_eip = parent_eip;
+	point->v = v;
+	ipipe_read_tsc(point->timestamp);
+
+	__ipipe_store_domain_states(point);
+
+	/* forward to next point buffer */
+	next_pos = WRAP_POINT_NO(pos+1);
+	tp->trace_pos = next_pos;
+
+	/* only mark beginning if we haven't started yet */
+	begin = tp->begin;
+	if (unlikely(type == IPIPE_TRACE_BEGIN) && (begin < 0))
+		tp->begin = pos;
+
+	/* end of critical path, start post-trace if not already started */
+	if (unlikely(type == IPIPE_TRACE_END) &&
+	    (begin >= 0) && !tp->post_trace)
+		tp->post_trace = post_trace + 1;
+
+	/* freeze only if the slot is free and we are not already freezing */
+	if ((unlikely(type == IPIPE_TRACE_FREEZE) ||
+	     (unlikely(eip >= trigger_begin && eip <= trigger_end) &&
+	     type == IPIPE_TRACE_FUNC)) &&
+	    per_cpu(trace_path, cpu)[per_cpu(frozen_path, cpu)].begin < 0 &&
+	    !(tp->flags & IPIPE_TFLG_FREEZING)) {
+		tp->post_trace = post_trace + 1;
+		tp->flags |= IPIPE_TFLG_FREEZING;
+	}
+
+	/* enforce end of trace in case of overflow */
+	if (unlikely(WRAP_POINT_NO(next_pos + 1) == begin)) {
+		tp->end = pos;
+		goto enforce_end;
+	}
+
+	/* stop tracing this path if we are in post-trace and
+	 *  a) that phase is over now or
+	 *  b) a new TRACE_BEGIN came in but we are not freezing this path */
+	if (unlikely((tp->post_trace > 0) && ((--tp->post_trace == 0) ||
+	             ((type == IPIPE_TRACE_BEGIN) &&
+	              !(tp->flags & IPIPE_TFLG_FREEZING))))) {
+		/* store the path's end (i.e. excluding post-trace) */
+		tp->end = WRAP_POINT_NO(pos - post_trace + tp->post_trace);
+
+ enforce_end:
+		if (tp->flags & IPIPE_TFLG_FREEZING)
+			tp = __ipipe_trace_freeze(cpu, tp, pos);
+		else
+			tp = __ipipe_trace_end(cpu, tp, pos);
+
+		/* reset the active path, maybe already start a new one */
+		tp->begin = (type == IPIPE_TRACE_BEGIN) ?
+			WRAP_POINT_NO(tp->trace_pos - 1) : -1;
+		tp->end = -1;
+		tp->post_trace = 0;
+		tp->flags = 0;
+
+		/* update active_path not earlier to avoid races with NMIs */
+		per_cpu(active_path, cpu) = tp - per_cpu(trace_path, cpu);
+	}
+
+	/* we still have old_tp and point,
+	 * let's reset NMI lock and check for catches */
+	old_tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+	if (unlikely(old_tp->flags & IPIPE_TFLG_NMI_HIT)) {
+		/* well, this late tagging may not immediately be visible for
+		 * other cpus already dumping this path - a minor issue */
+		point->flags |= IPIPE_TFLG_NMI_HIT;
+
+		/* handle deferred freezing from NMI context */
+		if (old_tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+			__ipipe_trace(IPIPE_TRACE_FREEZE, old_tp->nmi_saved_eip,
+			              old_tp->nmi_saved_parent_eip,
+			              old_tp->nmi_saved_v);
+	}
+
+	local_irq_restore_hw_notrace(flags);
+}
+
+static unsigned long __ipipe_global_path_lock(void)
+{
+	unsigned long flags;
+	int cpu;
+	struct ipipe_trace_path *tp;
+
+	spin_lock_irqsave(&global_path_lock, flags);
+
+	cpu = ipipe_processor_id();
+ restart:
+	tp = &per_cpu(trace_path, cpu)[per_cpu(active_path, cpu)];
+
+	/* here is small race window with NMIs - catched below */
+
+	/* clear NMI events and set lock (atomically per cpu) */
+	tp->flags = (tp->flags & ~(IPIPE_TFLG_NMI_HIT |
+	                           IPIPE_TFLG_NMI_FREEZE_REQ))
+	                       | IPIPE_TFLG_NMI_LOCK;
+
+	/* check active_path again - some nasty NMI may have switched
+	 * it meanwhile */
+	if (tp != &per_cpu(trace_path, cpu)[per_cpu(active_path, cpu)]) {
+		/* release lock on wrong path and restart */
+		tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+		/* there is no chance that the NMI got deferred
+		 * => no need to check for pending freeze requests */
+		goto restart;
+	}
+
+	return flags;
+}
+
+static void __ipipe_global_path_unlock(unsigned long flags)
+{
+	int cpu;
+	struct ipipe_trace_path *tp;
+
+	/* release spinlock first - it's not involved in the NMI issue */
+	__ipipe_spin_unlock_irqbegin(&global_path_lock);
+
+	cpu = ipipe_processor_id();
+	tp = &per_cpu(trace_path, cpu)[per_cpu(active_path, cpu)];
+
+	tp->flags &= ~IPIPE_TFLG_NMI_LOCK;
+
+	/* handle deferred freezing from NMI context */
+	if (tp->flags & IPIPE_TFLG_NMI_FREEZE_REQ)
+		__ipipe_trace(IPIPE_TRACE_FREEZE, tp->nmi_saved_eip,
+		              tp->nmi_saved_parent_eip, tp->nmi_saved_v);
+
+	/* See __ipipe_spin_lock_irqsave() and friends. */
+	__ipipe_spin_unlock_irqcomplete(flags);
+}
+
+void notrace ipipe_trace_begin(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_BEGIN, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_begin);
+
+void notrace ipipe_trace_end(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_END, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_end);
+
+void notrace ipipe_trace_freeze(unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_FREEZE, __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_freeze);
+
+void notrace ipipe_trace_special(unsigned char id, unsigned long v)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_SPECIAL | (id << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, v);
+}
+EXPORT_SYMBOL(ipipe_trace_special);
+
+void notrace ipipe_trace_pid(pid_t pid, short prio)
+{
+	if (!ipipe_trace_enable)
+		return;
+	__ipipe_trace(IPIPE_TRACE_PID | (prio << IPIPE_TYPE_BITS),
+	              __BUILTIN_RETURN_ADDRESS0,
+	              __BUILTIN_RETURN_ADDRESS1, pid);
+}
+EXPORT_SYMBOL(ipipe_trace_pid);
+
+int ipipe_trace_max_reset(void)
+{
+	int cpu;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_possible_cpu(cpu) {
+		path = &per_cpu(trace_path, cpu)[per_cpu(max_path, cpu)];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin     = -1;
+		path->end       = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_max_reset);
+
+int ipipe_trace_frozen_reset(void)
+{
+	int cpu;
+	unsigned long flags;
+	struct ipipe_trace_path *path;
+	int ret = 0;
+
+	flags = __ipipe_global_path_lock();
+
+	for_each_online_cpu(cpu) {
+		path = &per_cpu(trace_path, cpu)[per_cpu(frozen_path, cpu)];
+
+		if (path->dump_lock) {
+			ret = -EBUSY;
+			break;
+		}
+
+		path->begin = -1;
+		path->end = -1;
+		path->trace_pos = 0;
+		path->length    = 0;
+	}
+
+	__ipipe_global_path_unlock(flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipipe_trace_frozen_reset);
+
+static void
+__ipipe_get_task_info(char *task_info, struct ipipe_trace_point *point,
+                      int trylock)
+{
+	struct task_struct *task = NULL;
+	char buf[8];
+	int i;
+	int locked = 1;
+
+	if (trylock) {
+		if (!read_trylock(&tasklist_lock))
+			locked = 0;
+	} else
+		read_lock(&tasklist_lock);
+
+	if (locked)
+		task = find_task_by_pid((pid_t)point->v);
+
+	if (task)
+		strncpy(task_info, task->comm, 11);
+	else
+		strcpy(task_info, "-<?>-");
+
+	if (locked)
+		read_unlock(&tasklist_lock);
+
+	for (i = strlen(task_info); i < 11; i++)
+		task_info[i] = ' ';
+
+	sprintf(buf, " %d ", point->type >> IPIPE_TYPE_BITS);
+	strcpy(task_info + (11 - strlen(buf)), buf);
+}
+
+#ifdef CONFIG_IPIPE_TRACE_PANIC
+void ipipe_trace_panic_freeze(void)
+{
+	unsigned long flags;
+	int cpu;
+
+	if (!ipipe_trace_enable)
+		return;
+
+	ipipe_trace_enable = 0;
+	local_irq_save_hw_notrace(flags);
+
+	cpu = ipipe_processor_id();
+
+	panic_path = &per_cpu(trace_path, cpu)[per_cpu(active_path, cpu)];
+
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(ipipe_trace_panic_freeze);
+
+void ipipe_trace_panic_dump(void)
+{
+	int cnt = back_trace;
+	int start, pos;
+	char task_info[12];
+
+	if (!panic_path)
+		return;
+
+	ipipe_context_check_off();
+
+	printk("I-pipe tracer log (%d points):\n", cnt);
+
+	start = pos = WRAP_POINT_NO(panic_path->trace_pos-1);
+
+	while (cnt-- > 0) {
+		struct ipipe_trace_point *point = &panic_path->point[pos];
+		long time;
+		char buf[16];
+		int i;
+
+		printk(" %c",
+		       (point->flags & IPIPE_TFLG_HWIRQ_OFF) ? '|' : ' ');
+
+		for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+			printk("%c",
+			       (IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+				(IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+					'#' : '+') :
+				(IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+					'*' : ' '));
+
+		if (!point->eip)
+			printk("-<invalid>-\n");
+		else {
+			__ipipe_trace_point_type(buf, point);
+			printk(buf);
+
+			switch (point->type & IPIPE_TYPE_MASK) {
+				case IPIPE_TRACE_FUNC:
+					printk("           ");
+					break;
+
+				case IPIPE_TRACE_PID:
+					__ipipe_get_task_info(task_info,
+							      point, 1);
+					printk(task_info);
+					break;
+
+				default:
+					printk("0x%08lx ", point->v);
+			}
+
+			time = __ipipe_signed_tsc2us(point->timestamp -
+				panic_path->point[start].timestamp);
+			printk(" %5ld ", time);
+
+			__ipipe_print_symname(NULL, point->eip);
+			printk(" (");
+			__ipipe_print_symname(NULL, point->parent_eip);
+			printk(")\n");
+		}
+		pos = WRAP_POINT_NO(pos - 1);
+	}
+
+	panic_path = NULL;
+}
+EXPORT_SYMBOL(ipipe_trace_panic_dump);
+#endif /* CONFIG_IPIPE_TRACE_PANIC */
+
+
+/* --- /proc output --- */
+
+static notrace int __ipipe_in_critical_trpath(long point_no)
+{
+	return ((WRAP_POINT_NO(point_no-print_path->begin) <
+	         WRAP_POINT_NO(print_path->end-print_path->begin)) ||
+	        ((print_path->end == print_path->begin) &&
+	         (WRAP_POINT_NO(point_no-print_path->end) >
+	          print_post_trace)));
+}
+
+static long __ipipe_signed_tsc2us(long long tsc)
+{
+        unsigned long long abs_tsc;
+        long us;
+
+	/* ipipe_tsc2us works on unsigned => handle sign separately */
+        abs_tsc = (tsc >= 0) ? tsc : -tsc;
+        us = ipipe_tsc2us(abs_tsc);
+        if (tsc < 0)
+                return -us;
+        else
+                return us;
+}
+
+static void
+__ipipe_trace_point_type(char *buf, struct ipipe_trace_point *point)
+{
+	switch (point->type & IPIPE_TYPE_MASK) {
+		case IPIPE_TRACE_FUNC:
+			strcpy(buf, "func    ");
+			break;
+
+		case IPIPE_TRACE_BEGIN:
+			strcpy(buf, "begin   ");
+			break;
+
+		case IPIPE_TRACE_END:
+			strcpy(buf, "end     ");
+			break;
+
+		case IPIPE_TRACE_FREEZE:
+			strcpy(buf, "freeze  ");
+			break;
+
+		case IPIPE_TRACE_SPECIAL:
+			sprintf(buf, "(0x%02x)  ",
+				point->type >> IPIPE_TYPE_BITS);
+			break;
+
+		case IPIPE_TRACE_PID:
+			sprintf(buf, "[%5d] ", (pid_t)point->v);
+			break;
+	}
+}
+
+static void
+__ipipe_print_pathmark(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	char mark = ' ';
+	int point_no = point - print_path->point;
+	int i;
+
+	if (print_path->end == point_no)
+		mark = '<';
+	else if (print_path->begin == point_no)
+		mark = '>';
+	else if (__ipipe_in_critical_trpath(point_no))
+		mark = ':';
+	seq_printf(m, "%c%c", mark,
+	           (point->flags & IPIPE_TFLG_HWIRQ_OFF) ? '|' : ' ');
+
+	if (!verbose_trace)
+		return;
+
+	for (i = IPIPE_TFLG_DOMSTATE_BITS; i >= 0; i--)
+		seq_printf(m, "%c",
+			(IPIPE_TFLG_CURRENT_DOMAIN(point) == i) ?
+			    (IPIPE_TFLG_DOMAIN_STALLED(point, i) ?
+				'#' : '+') :
+			(IPIPE_TFLG_DOMAIN_STALLED(point, i) ? '*' : ' '));
+}
+
+static void
+__ipipe_print_delay(struct seq_file *m, struct ipipe_trace_point *point)
+{
+	unsigned long delay = 0;
+	int next;
+	char *mark = "  ";
+
+	next = WRAP_POINT_NO(point+1 - print_path->point);
+
+	if (next != print_path->trace_pos)
+		delay = ipipe_tsc2ns(print_path->point[next].timestamp -
+		                     point->timestamp);
+
+	if (__ipipe_in_critical_trpath(point - print_path->point)) {
+		if (delay > IPIPE_DELAY_WARN)
+			mark = "! ";
+		else if (delay > IPIPE_DELAY_NOTE)
+			mark = "+ ";
+	}
+	seq_puts(m, mark);
+
+	if (verbose_trace)
+		seq_printf(m, "%3lu.%03lu%c ", delay/1000, delay%1000,
+		           (point->flags & IPIPE_TFLG_NMI_HIT) ? 'N' : ' ');
+	else
+		seq_puts(m, " ");
+}
+
+static void __ipipe_print_symname(struct seq_file *m, unsigned long eip)
+{
+	char namebuf[KSYM_NAME_LEN+1];
+	unsigned long size, offset;
+	const char *sym_name;
+	char *modname;
+
+	sym_name = kallsyms_lookup(eip, &size, &offset, &modname, namebuf);
+
+#ifdef CONFIG_IPIPE_TRACE_PANIC
+	if (!m) {
+		/* panic dump */
+		if (sym_name) {
+			printk("%s+0x%lx", sym_name, offset);
+			if (modname)
+				printk(" [%s]", modname);
+		}
+	} else
+#endif /* CONFIG_IPIPE_TRACE_PANIC */
+	{
+		if (sym_name) {
+			if (verbose_trace) {
+				seq_printf(m, "%s+0x%lx", sym_name, offset);
+				if (modname)
+					seq_printf(m, " [%s]", modname);
+			} else
+				seq_puts(m, sym_name);
+		} else
+			seq_printf(m, "<%08lx>", eip);
+	}
+}
+
+static void __ipipe_print_headline(struct seq_file *m)
+{
+	seq_printf(m, "Calibrated minimum trace-point overhead: %lu.%03lu "
+		   "us\n\n", trace_overhead/1000, trace_overhead%1000);
+
+	if (verbose_trace) {
+		const char *name[4] = { [0 ... 3] = "<unused>" };
+		struct list_head *pos;
+		int i = 0;
+
+		list_for_each_prev(pos, &__ipipe_pipeline) {
+			struct ipipe_domain *ipd =
+				list_entry(pos, struct ipipe_domain, p_link);
+
+			name[i] = ipd->name;
+			if (++i > 3)
+				break;
+		}
+
+		seq_printf(m,
+		           " +----- Hard IRQs ('|': locked)\n"
+		           " |+---- %s\n"
+		           " ||+--- %s\n"
+		           " |||+-- %s\n"
+		           " ||||+- %s%s\n"
+		           " |||||                        +---------- "
+		               "Delay flag ('+': > %d us, '!': > %d us)\n"
+		           " |||||                        |        +- "
+		               "NMI noise ('N')\n"
+		           " |||||                        |        |\n"
+		           "      Type    User Val.   Time    Delay  Function "
+		               "(Parent)\n",
+		           name[3], name[2], name[1], name[0],
+		           name[0] ? " ('*': domain stalled, '+': current, "
+		               "'#': current+stalled)" : "",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+	} else
+		seq_printf(m,
+		           " +--------------- Hard IRQs ('|': locked)\n"
+		           " |             +- Delay flag "
+		               "('+': > %d us, '!': > %d us)\n"
+		           " |             |\n"
+		           "  Type     Time   Function (Parent)\n",
+		           IPIPE_DELAY_NOTE/1000, IPIPE_DELAY_WARN/1000);
+}
+
+static void *__ipipe_max_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	mutex_lock(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *tp;
+		unsigned long length_usecs;
+		int points, cpu;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the longest of all per-cpu paths */
+		print_path = NULL;
+		for_each_online_cpu(cpu) {
+			tp = &per_cpu(trace_path, cpu)[per_cpu(max_path, cpu)];
+			if ((print_path == NULL) ||
+			    (tp->length > print_path->length)) {
+				print_path = tp;
+				break;
+			}
+		}
+		print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		/* does this path actually contain data? */
+		if (print_path->end == print_path->begin)
+			return NULL;
+
+		/* number of points inside the critical path */
+		points = WRAP_POINT_NO(print_path->end-print_path->begin+1);
+
+		/* pre- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, pre-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = pre_trace;
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (points+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 1 - points -
+				print_post_trace;
+
+		length_usecs = ipipe_tsc2us(print_path->length);
+		seq_printf(m, "I-pipe worst-case tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		seq_printf(m, "CPU: %d, Begin: %lld cycles, Trace Points: "
+			"%d (-%d/+%d), Length: %lu us\n",
+			cpu, print_path->point[print_path->begin].timestamp,
+			points, print_pre_trace, print_post_trace, length_usecs);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + n)];
+}
+
+static void *__ipipe_prtrace_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	loff_t n = ++*pos;
+
+	/* check if we are inside the trace range with the next entry */
+	if (n >= WRAP_POINT_NO(print_path->end - print_path->begin + 1 +
+	                       print_pre_trace + print_post_trace))
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin -
+	                                        print_pre_trace + *pos)];
+}
+
+static void __ipipe_prtrace_stop(struct seq_file *m, void *p)
+{
+	if (print_path)
+		print_path->dump_lock = 0;
+	mutex_unlock(&out_mutex);
+}
+
+static int __ipipe_prtrace_show(struct seq_file *m, void *p)
+{
+	long time;
+	struct ipipe_trace_point *point = p;
+	char buf[16];
+
+	if (!point->eip) {
+		seq_puts(m, "-<invalid>-\n");
+		return 0;
+	}
+
+	__ipipe_print_pathmark(m, point);
+	__ipipe_trace_point_type(buf, point);
+	seq_puts(m, buf);
+	if (verbose_trace)
+		switch (point->type & IPIPE_TYPE_MASK) {
+			case IPIPE_TRACE_FUNC:
+				seq_puts(m, "           ");
+				break;
+
+			case IPIPE_TRACE_PID:
+				__ipipe_get_task_info(buf, point, 0);
+				seq_puts(m, buf);
+				break;
+
+			default:
+				seq_printf(m, "0x%08lx ", point->v);
+		}
+
+	time = __ipipe_signed_tsc2us(point->timestamp -
+		print_path->point[print_path->begin].timestamp);
+	seq_printf(m, "%5ld", time);
+
+	__ipipe_print_delay(m, point);
+	__ipipe_print_symname(m, point->eip);
+	seq_puts(m, " (");
+	__ipipe_print_symname(m, point->parent_eip);
+	seq_puts(m, ")\n");
+
+	return 0;
+}
+
+static struct seq_operations __ipipe_max_ptrace_ops = {
+	.start = __ipipe_max_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_max_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_max_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_max_reset(struct file *file, const char __user *pbuffer,
+                  size_t count, loff_t *data)
+{
+	mutex_lock(&out_mutex);
+	ipipe_trace_max_reset();
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_max_prtrace_fops = {
+	.open       = __ipipe_max_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_max_reset,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static void *__ipipe_frozen_prtrace_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+
+	mutex_lock(&out_mutex);
+
+	if (!n) {
+		struct ipipe_trace_path *tp;
+		int cpu;
+		unsigned long flags;
+
+		/* protect against max_path/frozen_path updates while we
+		 * haven't locked our target path, also avoid recursively
+		 * taking global_path_lock from NMI context */
+		flags = __ipipe_global_path_lock();
+
+		/* find the first of all per-cpu frozen paths */
+		print_path = NULL;
+		for_each_online_cpu(cpu) {
+			tp = &per_cpu(trace_path, cpu)[per_cpu(frozen_path, cpu)];
+			if (tp->end >= 0) {
+				print_path = tp;
+				break;
+			}
+		}
+		if (print_path)
+			print_path->dump_lock = 1;
+
+		__ipipe_global_path_unlock(flags);
+
+		if (!print_path)
+			return NULL;
+
+		/* back- and post-tracing length, post-trace length was frozen
+		   in __ipipe_trace, back-trace may have to be reduced due to
+		   buffer overrun */
+		print_pre_trace  = back_trace-1; /* substract freeze point */
+		print_post_trace = WRAP_POINT_NO(print_path->trace_pos -
+		                                 print_path->end - 1);
+		if (1+pre_trace+print_post_trace > IPIPE_TRACE_POINTS - 1)
+			print_pre_trace = IPIPE_TRACE_POINTS - 2 -
+				print_post_trace;
+
+		seq_printf(m, "I-pipe frozen back-tracing service on %s/ipipe-%s\n"
+			"------------------------------------------------------"
+			"------\n",
+			UTS_RELEASE, IPIPE_ARCH_STRING);
+		seq_printf(m, "CPU: %d, Freeze: %lld cycles, Trace Points: %d (+%d)\n",
+			cpu, print_path->point[print_path->begin].timestamp,
+			print_pre_trace+1, print_post_trace);
+		__ipipe_print_headline(m);
+	}
+
+	/* check if we are inside the trace range */
+	if (n >= print_pre_trace + 1 + print_post_trace)
+		return NULL;
+
+	/* return the next point to be shown */
+	return &print_path->point[WRAP_POINT_NO(print_path->begin-
+	                                        print_pre_trace+n)];
+}
+
+static struct seq_operations __ipipe_frozen_ptrace_ops = {
+	.start = __ipipe_frozen_prtrace_start,
+	.next  = __ipipe_prtrace_next,
+	.stop  = __ipipe_prtrace_stop,
+	.show  = __ipipe_prtrace_show
+};
+
+static int __ipipe_frozen_prtrace_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &__ipipe_frozen_ptrace_ops);
+}
+
+static ssize_t
+__ipipe_frozen_ctrl(struct file *file, const char __user *pbuffer,
+                    size_t count, loff_t *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, pbuffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	mutex_lock(&out_mutex);
+	ipipe_trace_frozen_reset();
+	if (val > 0)
+		ipipe_trace_freeze(-1);
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+struct file_operations __ipipe_frozen_prtrace_fops = {
+	.open       = __ipipe_frozen_prtrace_open,
+	.read       = seq_read,
+	.write      = __ipipe_frozen_ctrl,
+	.llseek     = seq_lseek,
+	.release    = seq_release,
+};
+
+static int __ipipe_rd_proc_val(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%u\n", *(int *)data);
+	len -= off;
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_wr_proc_val(struct file *file, const char __user *buffer,
+                               unsigned long count, void *data)
+{
+	char *end, buf[16];
+	int val;
+	int n;
+
+	n = (count > sizeof(buf) - 1) ? sizeof(buf) - 1 : count;
+
+	if (copy_from_user(buf, buffer, n))
+		return -EFAULT;
+
+	buf[n] = '\0';
+	val = simple_strtol(buf, &end, 0);
+
+	if (((*end != '\0') && !isspace(*end)) || (val < 0))
+		return -EINVAL;
+
+	mutex_lock(&out_mutex);
+	*(int *)data = val;
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+/* Look up a kernel symbol and return it in a text buffer. */
+static int sprint_symbol(char *buffer, unsigned long address)
+{
+	char *modname;
+	const char *name;
+	unsigned long offset, size;
+	char namebuf[KSYM_NAME_LEN+1];
+
+	name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
+	if (!name)
+		return sprintf(buffer, "0x%lx", address);
+	else {
+		if (modname)
+			return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
+				size, modname);
+		else
+			return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+	}
+}
+
+static int __ipipe_rd_trigger(char *page, char **start, off_t off, int count,
+			      int *eof, void *data)
+{
+	int len;
+
+	if (!trigger_begin)
+		return 0;
+
+	len = sprint_symbol(page, trigger_begin);
+	page[len++] = '\n';
+
+	len -= off;
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int __ipipe_wr_trigger(struct file *file, const char __user *buffer,
+			      unsigned long count, void *data)
+{
+	char buf[KSYM_NAME_LEN+1];
+	unsigned long begin, end;
+
+	if (count > sizeof(buf) - 1)
+		count = sizeof(buf) - 1;
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+	buf[count] = 0;
+	if (buf[count-1] == '\n')
+		buf[count-1] = 0;
+
+	begin = kallsyms_lookup_name(buf);
+	if (!begin || !kallsyms_lookup_size_offset(begin, &end, NULL))
+		return -ENOENT;
+	end += begin - 1;
+
+	mutex_lock(&out_mutex);
+	/* invalidate the current range before setting a new one */
+	trigger_end = 0;
+	wmb();
+	ipipe_trace_frozen_reset();
+
+	/* set new range */
+	trigger_begin = begin;
+	wmb();
+	trigger_end = end;
+	mutex_unlock(&out_mutex);
+
+	return count;
+}
+
+extern struct proc_dir_entry *ipipe_proc_root;
+
+static void __init
+__ipipe_create_trace_proc_val(struct proc_dir_entry *trace_dir,
+                              const char *name, int *value_ptr)
+{
+	struct proc_dir_entry *entry;
+
+	entry = create_proc_entry(name, 0644, trace_dir);
+	if (entry) {
+		entry->data = value_ptr;
+		entry->read_proc = __ipipe_rd_proc_val;
+		entry->write_proc = __ipipe_wr_proc_val;
+		entry->owner = THIS_MODULE;
+	}
+}
+
+void __init __ipipe_init_tracer(void)
+{
+	struct proc_dir_entry *trace_dir;
+	struct proc_dir_entry *entry;
+	unsigned long long start, end, min = ULLONG_MAX;
+	int i;
+#ifdef CONFIG_IPIPE_TRACE_VMALLOC
+	int cpu, path;
+
+	for_each_possible_cpu(cpu) {
+		struct ipipe_trace_path *tp_buf;
+
+		tp_buf = vmalloc_node(sizeof(struct ipipe_trace_path) *
+				      IPIPE_TRACE_PATHS, cpu_to_node(cpu));
+		if (!tp_buf) {
+			printk(KERN_ERR "I-pipe: "
+			       "insufficient memory for trace buffer.\n");
+			return;
+		}
+		memset(tp_buf, 0,
+		       sizeof(struct ipipe_trace_path) * IPIPE_TRACE_PATHS);
+		for (path = 0; path < IPIPE_TRACE_PATHS; path++) {
+			tp_buf[path].begin = -1;
+			tp_buf[path].end   = -1;
+		}
+		per_cpu(trace_path, cpu) = tp_buf;
+	}
+#endif /* CONFIG_IPIPE_TRACE_VMALLOC */
+	ipipe_trace_enable = CONFIG_IPIPE_TRACE_ENABLE_VALUE;
+
+	/* Calculate minimum overhead of __ipipe_trace() */
+	local_irq_disable_hw();
+	for (i = 0; i < 100; i++) {
+		ipipe_read_tsc(start);
+		__ipipe_trace(IPIPE_TRACE_FUNC, __BUILTIN_RETURN_ADDRESS0,
+			      __BUILTIN_RETURN_ADDRESS1, 0);
+		ipipe_read_tsc(end);
+
+		end -= start;
+		if (end < min)
+			min = end;
+	}
+	local_irq_enable_hw();
+	trace_overhead = ipipe_tsc2ns(min);
+
+	trace_dir = create_proc_entry("trace", S_IFDIR, ipipe_proc_root);
+
+	entry = create_proc_entry("max", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_max_prtrace_fops;
+
+	entry = create_proc_entry("frozen", 0644, trace_dir);
+	if (entry)
+		entry->proc_fops = &__ipipe_frozen_prtrace_fops;
+
+	entry = create_proc_entry("trigger", 0644, trace_dir);
+	if (entry) {
+		entry->read_proc = __ipipe_rd_trigger;
+		entry->write_proc = __ipipe_wr_trigger;
+		entry->owner = THIS_MODULE;
+	}
+
+	__ipipe_create_trace_proc_val(trace_dir, "pre_trace_points",
+	                              &pre_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "post_trace_points",
+	                              &post_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "back_trace_points",
+	                              &back_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "verbose",
+	                              &verbose_trace);
+	__ipipe_create_trace_proc_val(trace_dir, "enable",
+	                              &ipipe_trace_enable);
+}
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index d27b258..96723be 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -308,7 +308,9 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
 	irqreturn_t action_ret;
 
 	spin_lock(&desc->lock);
+#ifndef CONFIG_IPIPE
 	mask_ack_irq(desc, irq);
+#endif /* CONFIG_IPIPE */
 
 	if (unlikely(desc->status & IRQ_INPROGRESS))
 		goto out_unlock;
@@ -386,8 +388,13 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
 
 	spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
+#ifdef CONFIG_IPIPE
+	desc->chip->unmask(irq);
+out:
+#else
 out:
 	desc->chip->eoi(irq);
+#endif
 
 	spin_unlock(&desc->lock);
 }
@@ -431,8 +438,10 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
 
 	kstat_cpu(cpu).irqs[irq]++;
 
+#ifndef CONFIG_IPIPE
 	/* Start handling the irq */
 	desc->chip->ack(irq);
+#endif /* CONFIG_IPIPE */
 
 	/* Mark the IRQ currently in progress.*/
 	desc->status |= IRQ_INPROGRESS;
@@ -472,6 +481,69 @@ out_unlock:
 	spin_unlock(&desc->lock);
 }
 
+#ifdef CONFIG_IPIPE
+
+void fastcall __ipipe_ack_simple_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_end_simple_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_ack_level_irq(unsigned irq, struct irq_desc *desc)
+{
+	mask_ack_irq(desc, irq);
+}
+
+void fastcall __ipipe_end_level_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->unmask)
+		desc->chip->unmask(irq);
+}
+
+void fastcall __ipipe_ack_fasteoi_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->eoi(irq);
+}
+
+void fastcall __ipipe_end_fasteoi_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->unmask(irq);
+}
+
+void fastcall __ipipe_ack_edge_irq(unsigned irq, struct irq_desc *desc)
+{
+	desc->chip->ack(irq);
+}
+
+void fastcall __ipipe_end_edge_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_ack_bad_irq(unsigned irq, struct irq_desc *desc)
+{
+	static int done;
+
+	handle_bad_irq(irq, desc);
+
+	if (!done) {
+		printk(KERN_WARNING "%s: unknown flow handler for IRQ %d\n",
+		       __FUNCTION__, irq);
+		done = 1;
+	}
+}
+
+void fastcall __ipipe_noack_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+void fastcall __ipipe_noend_irq(unsigned irq, struct irq_desc *desc)
+{
+}
+
+#endif /* CONFIG_IPIPE */
+
 #ifdef CONFIG_SMP
 /**
  *	handle_percpu_IRQ - Per CPU local irq handler
@@ -487,8 +559,10 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
 
 	kstat_this_cpu.irqs[irq]++;
 
+#ifndef CONFIG_IPIPE
 	if (desc->chip->ack)
 		desc->chip->ack(irq);
+#endif /* CONFIG_IPIPE */
 
 	action_ret = handle_IRQ_event(irq, desc->action);
 	if (!noirqdebug)
@@ -498,6 +572,22 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
 		desc->chip->eoi(irq);
 }
 
+#ifdef CONFIG_IPIPE
+
+void fastcall __ipipe_ack_percpu_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->ack)
+		desc->chip->ack(irq);
+}
+
+void fastcall __ipipe_end_percpu_irq(unsigned irq, struct irq_desc *desc)
+{
+	if (desc->chip->eoi)
+		desc->chip->eoi(irq);
+}
+
+#endif /* CONFIG_IPIPE */
+
 #endif /* CONFIG_SMP */
 
 void
@@ -517,6 +607,30 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 
 	if (!handle)
 		handle = handle_bad_irq;
+#ifdef CONFIG_IPIPE
+	else if (handle == &handle_simple_irq) {
+		desc->ipipe_ack = &__ipipe_ack_simple_irq;
+		desc->ipipe_end = &__ipipe_end_simple_irq;
+	}
+	else if (handle == &handle_level_irq) {
+		desc->ipipe_ack = &__ipipe_ack_level_irq;
+		desc->ipipe_end = &__ipipe_end_level_irq;
+	}
+	else if (handle == &handle_edge_irq) {
+		desc->ipipe_ack = &__ipipe_ack_edge_irq;
+		desc->ipipe_end = &__ipipe_end_edge_irq;
+	}
+	else if (handle == &handle_fasteoi_irq) {
+		desc->ipipe_ack = &__ipipe_ack_fasteoi_irq;
+		desc->ipipe_end = &__ipipe_end_fasteoi_irq;
+	}
+#ifdef CONFIG_SMP
+	else if (handle == &handle_percpu_irq) {
+		desc->ipipe_ack = &__ipipe_ack_percpu_irq;
+		desc->ipipe_end = &__ipipe_end_percpu_irq;
+	}
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_IPIPE */
 	else if (desc->chip == &no_irq_chip) {
 		printk(KERN_WARNING "Trying to install %sinterrupt handler "
 		       "for IRQ%d\n", is_chained ? "chained " : "", irq);
@@ -528,7 +642,17 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 		 * dummy_irq_chip for easy transition.
 		 */
 		desc->chip = &dummy_irq_chip;
+#ifdef CONFIG_IPIPE
+		desc->ipipe_ack = &__ipipe_noack_irq;
+		desc->ipipe_end = &__ipipe_noend_irq;
+#endif /* CONFIG_IPIPE */
 	}
+#ifdef CONFIG_IPIPE
+ 	else {
+ 		desc->ipipe_ack = &__ipipe_ack_bad_irq;
+ 		desc->ipipe_end = &__ipipe_noend_irq;
+ 	}
+#endif /* CONFIG_IPIPE */
 
 	spin_lock_irqsave(&desc->lock, flags);
 
@@ -540,6 +664,10 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 		}
 		desc->status |= IRQ_DISABLED;
 		desc->depth = 1;
+#ifdef CONFIG_IPIPE
+		desc->ipipe_ack = &__ipipe_ack_bad_irq;
+		desc->ipipe_end = &__ipipe_noend_irq;
+#endif /* CONFIG_IPIPE */
 	}
 	desc->handle_irq = handle;
 	desc->name = name;
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index aff1f0f..fd17c64 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -61,6 +61,8 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = {
 	}
 };
 
+EXPORT_SYMBOL(irq_desc);
+
 /*
  * What should we do if we get a hw irq event on an illegal vector?
  * Each architecture has to answer this themself.
@@ -131,7 +133,12 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
 {
 	irqreturn_t ret, retval = IRQ_NONE;
 	unsigned int status = 0;
+	struct pt_regs *regs = get_irq_regs();
 
+	MARK(kernel_irq_entry, "%u %u", irq, (regs)?(!user_mode(regs)):(1));
+	MARK(stack_arch_irq_dump_kernel_stack, MARK_NOARGS, regs);
+	MARK(stack_arch_irq_dump_process32_stack, MARK_NOARGS, regs);
+	MARK(stack_arch_irq_dump_process64_stack, MARK_NOARGS, regs);
 	handle_dynamic_tick(action);
 
 	if (!(action->flags & IRQF_DISABLED))
@@ -149,6 +156,8 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
 		add_interrupt_randomness(irq);
 	local_irq_disable();
 
+	MARK(kernel_irq_exit, MARK_NOARGS);
+
 	return retval;
 }
 
@@ -177,16 +186,20 @@ fastcall unsigned int __do_IRQ(unsigned int irq)
 		/*
 		 * No locking required for CPU-local interrupts:
 		 */
+#ifndef CONFIG_IPIPE
 		if (desc->chip->ack)
 			desc->chip->ack(irq);
+#endif
 		action_ret = handle_IRQ_event(irq, desc->action);
 		desc->chip->end(irq);
 		return 1;
 	}
 
 	spin_lock(&desc->lock);
+#ifndef CONFIG_IPIPE
 	if (desc->chip->ack)
 		desc->chip->ack(irq);
+#endif
 	/*
 	 * REPLAY is when Linux resends an IRQ that was dropped earlier
 	 * WAITING is used by probe to mark irqs that are being tested
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 204ed79..49e2ecf 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -133,6 +133,8 @@ int it_real_fn(struct hrtimer *timer)
 	struct signal_struct *sig =
 	    container_of(timer, struct signal_struct, real_timer);
 
+	MARK(kernel_timer_itimer_expired, "%d", sig->tsk->pid);
+
 	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, sig->tsk);
 
 	if (sig->it_real_incr.tv64 != 0) {
@@ -216,6 +218,15 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 	 */
 	check_itimerval(value);
 
+	MARK(kernel_timer_itimer_set, "%d %*.*r %*.*r",
+			which,
+			sizeof(value->it_interval),
+			__alignof__(value->it_interval),
+			&value->it_interval,
+			sizeof(value->it_value),
+			__alignof__(value->it_value),
+			&value->it_value);
+
 	switch (which) {
 	case ITIMER_REAL:
 again:
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 1db8c72..670bb8b 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -226,6 +226,8 @@ int kthread_stop(struct task_struct *k)
 	/* It could exit after stop_info.k set, but before wake_up_process. */
 	get_task_struct(k);
 
+	MARK(kernel_kthread_stop, "%d", k->pid);
+
 	/* Must init completion *before* thread sees kthread_stop_info.k */
 	init_completion(&kthread_stop_info.done);
 	smp_wmb();
@@ -241,6 +243,8 @@ int kthread_stop(struct task_struct *k)
 	ret = kthread_stop_info.err;
 	mutex_unlock(&kthread_stop_lock);
 
+	MARK(kernel_kthread_stop_ret, "%d", ret);
+
 	return ret;
 }
 EXPORT_SYMBOL(kthread_stop);
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 509efd4..103399f 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -1841,6 +1841,9 @@ void trace_hardirqs_on(void)
 	struct task_struct *curr = current;
 	unsigned long ip;
 
+	_MARK(_MF_DEFAULT & ~_MF_LOCKDEP, locking_hardirqs_on, "%lu",
+		(unsigned long) __builtin_return_address(0));
+
 	if (unlikely(!debug_locks || current->lockdep_recursion))
 		return;
 
@@ -1888,6 +1891,9 @@ void trace_hardirqs_off(void)
 {
 	struct task_struct *curr = current;
 
+	_MARK(_MF_DEFAULT & (~_MF_LOCKDEP), locking_hardirqs_off, "%lu",
+		(unsigned long) __builtin_return_address(0));
+
 	if (unlikely(!debug_locks || current->lockdep_recursion))
 		return;
 
@@ -1915,6 +1921,9 @@ void trace_softirqs_on(unsigned long ip)
 {
 	struct task_struct *curr = current;
 
+	_MARK(_MF_DEFAULT & ~_MF_LOCKDEP, locking_softirqs_on, "%lu",
+		(unsigned long) __builtin_return_address(0));
+
 	if (unlikely(!debug_locks))
 		return;
 
@@ -1949,6 +1958,9 @@ void trace_softirqs_off(unsigned long ip)
 {
 	struct task_struct *curr = current;
 
+	_MARK(_MF_DEFAULT & ~_MF_LOCKDEP, locking_softirqs_off, "%lu",
+		(unsigned long) __builtin_return_address(0));
+
 	if (unlikely(!debug_locks))
 		return;
 
@@ -2015,6 +2027,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 	int chain_head = 0;
 	u64 chain_key;
 
+	_MARK(_MF_DEFAULT & ~_MF_LOCKDEP, locking_lock_acquire,
+		"%lu %u %p %d", ip, subclass, lock, trylock);
+
 	if (unlikely(!debug_locks))
 		return 0;
 
@@ -2373,6 +2388,9 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
 {
 	struct task_struct *curr = current;
 
+	_MARK(_MF_DEFAULT & ~_MF_LOCKDEP, locking_lock_release,
+		"%lu %p %d", ip, lock, nested);
+
 	if (!check_unlock(curr, lock, ip))
 		return;
 
diff --git a/kernel/module.c b/kernel/module.c
index d0f2260..418f4d7 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -31,6 +31,7 @@
 #include <linux/cpu.h>
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
+#include <linux/marker.h>
 #include <linux/err.h>
 #include <linux/vermagic.h>
 #include <linux/notifier.h>
@@ -138,6 +139,8 @@ extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
 extern const unsigned long __start___kcrctab_unused[];
 extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const struct __mark_marker __start___markers[];
+extern const struct __mark_marker __stop___markers[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -298,6 +301,229 @@ static struct module *find_module(const char *name)
 	return NULL;
 }
 
+#ifdef CONFIG_MARKERS
+
+/* Empty callback provided as a probe to the markers. By providing this to a
+ * disabled marker, we makes sure the  execution flow is always valid even
+ * though the function pointer change and the marker enabling are two distinct
+ * operations that modifies the execution flow of preemptible code. */
+void __mark_empty_function(const struct __mark_marker_data *mdata,
+	const char *fmt, ...)
+{
+}
+EXPORT_SYMBOL_GPL(__mark_empty_function);
+
+/* Set the enable bit of the marker, choosing the generic or architecture
+ * specific functions depending on the marker's flags.
+ */
+static int marker_set_enable(void *address, char enable, int flags)
+{
+	if (flags & _MF_OPTIMIZED)
+		return marker_optimized_set_enable(address, enable);
+	else
+		return marker_generic_set_enable(address, enable);
+}
+
+/* Sets the probe callback and enables the markers corresponding to a range of
+ * markers. The enable bit and function address are set out of order, and it's
+ * ok : the state is always coherent because of the empty callback we provide.
+ */
+static int _marker_set_probe_range(int flags, const char *name,
+	const char *format,
+	marker_probe_func *probe,
+	void *pdata,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (strcmp(name, iter->mdata->name) == 0) {
+			if (format
+				&& strcmp(format, iter->mdata->format) != 0) {
+				printk(KERN_NOTICE
+					"Format mismatch for probe %s "
+					"(%s), marker (%s)\n",
+					name,
+					format,
+					iter->mdata->format);
+				continue;
+			}
+			if (flags & _MF_LOCKDEP
+				&& !(iter->mdata->flags & _MF_LOCKDEP)) {
+					printk(KERN_NOTICE
+					"Incompatible lockdep flags for "
+					"probe %s\n",
+					name);
+					continue;
+			}
+			if (flags & _MF_PRINTK
+				&& !(iter->mdata->flags & _MF_PRINTK)) {
+					printk(KERN_NOTICE
+					"Incompatible printk flags for "
+					"probe %s\n",
+					name);
+					continue;
+			}
+			if (probe == __mark_empty_function) {
+				if (iter->mdata->call
+					!= __mark_empty_function) {
+					iter->mdata->call =
+						__mark_empty_function;
+				}
+				marker_set_enable(iter->enable, 0,
+					iter->mdata->flags);
+			} else {
+				if (iter->mdata->call
+					!= __mark_empty_function) {
+					if (iter->mdata->call != probe) {
+						printk(KERN_NOTICE
+							"Marker %s busy, "
+							"probe %p already "
+							"installed\n",
+							name,
+							iter->mdata->call);
+						continue;
+					}
+				} else {
+					found++;
+					iter->mdata->call = probe;
+				}
+				iter->mdata->pdata = pdata;
+				smp_wmb();
+				marker_set_enable(iter->enable, 1,
+					iter->mdata->flags);
+			}
+			found++;
+		}
+	}
+	return found;
+}
+
+/* Sets a range of markers to a disabled state : unset the enable bit and
+ * provide the empty callback. */
+static int marker_remove_probe_range(const char *name,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (strcmp(name, iter->mdata->name) == 0) {
+			marker_set_enable(iter->enable, 0,
+				iter->mdata->flags);
+			iter->mdata->call = __mark_empty_function;
+			found++;
+		}
+	}
+	return found;
+}
+
+/* Provides a listing of the markers present in the kernel with their type
+ * (optimized or generic), state (enabled or disabled), callback and format
+ * string. */
+static int marker_list_probe_range(marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (probe)
+			if (probe != iter->mdata->call) continue;
+		printk("name %s \n", iter->mdata->name);
+		if (iter->mdata->flags & _MF_OPTIMIZED)
+			printk("  enable %u optimized ",
+				MARK_OPTIMIZED_ENABLE(iter->enable));
+		else
+			printk("  enable %u generic ",
+				MARK_GENERIC_ENABLE(iter->enable));
+		printk("  func 0x%p format \"%s\"\n",
+			iter->mdata->call, iter->mdata->format);
+		found++;
+	}
+	return found;
+}
+
+/* Calls _marker_set_probe_range for the core markers and modules markers.
+ * Marker enabling/disabling use the modlist_lock to synchronise. */
+int _marker_set_probe(int flags, const char *name, const char *format,
+				marker_probe_func *probe,
+				void *pdata)
+{
+	struct module *mod;
+	int found = 0;
+
+	mutex_lock(&module_mutex);
+	/* Core kernel markers */
+	found += _marker_set_probe_range(flags, name, format, probe,
+			pdata,	
+			__start___markers, __stop___markers);
+	/* Markers in modules. */
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints)
+			found += _marker_set_probe_range(flags, name, format,
+			probe, pdata,
+			mod->markers, mod->markers+mod->num_markers);
+	}
+	mutex_unlock(&module_mutex);
+	return found;
+}
+EXPORT_SYMBOL_GPL(_marker_set_probe);
+
+/* Calls _marker_remove_probe_range for the core markers and modules markers.
+ * Marker enabling/disabling use the modlist_lock to synchronise. */
+int marker_remove_probe(const char *name)
+{
+	struct module *mod;
+	int found = 0;
+
+	mutex_lock(&module_mutex);
+	/* Core kernel markers */
+	found += marker_remove_probe_range(name,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints)
+			found += marker_remove_probe_range(name,
+				mod->markers, mod->markers+mod->num_markers);
+	}
+	mutex_unlock(&module_mutex);
+	return found;
+}
+EXPORT_SYMBOL_GPL(marker_remove_probe);
+
+/* Calls _marker_list_probe_range for the core markers and modules markers.
+ * Marker listing uses the modlist_lock to synchronise.
+ * TODO : should output this listing to a procfs file. */
+int marker_list_probe(marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+
+	mutex_lock(&module_mutex);
+	/* Core kernel markers */
+	printk("Listing kernel markers\n");
+	found += marker_list_probe_range(probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */
+	printk("Listing module markers\n");
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints) {
+			printk("Listing markers for module %s\n", mod->name);
+			found += marker_list_probe_range(probe,
+				mod->markers, mod->markers+mod->num_markers);
+		}
+	}
+	mutex_unlock(&module_mutex);
+	return found;
+}
+EXPORT_SYMBOL_GPL(marker_list_probe);
+#endif
+
 #ifdef CONFIG_SMP
 /* Number of blocks used and allocated. */
 static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -1182,6 +1408,8 @@ static int __unlink_module(void *_mod)
 /* Free a module, remove from lists, etc (must hold module mutex). */
 static void free_module(struct module *mod)
 {
+	MARK(kernel_module_free, "%s", mod->name);
+
 	/* Delete from various lists */
 	stop_machine_run(__unlink_module, mod, NR_CPUS);
 	remove_sect_attrs(mod);
@@ -1561,6 +1789,9 @@ static struct module *load_module(void __user *umod,
 	unsigned int unusedcrcindex;
 	unsigned int unusedgplindex;
 	unsigned int unusedgplcrcindex;
+	unsigned int markersindex;
+	unsigned int markersdataindex;
+	unsigned int markersstringsindex;
 	struct module *mod;
 	long err = 0;
 	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1657,6 +1888,10 @@ static struct module *load_module(void __user *umod,
 #ifdef ARCH_UNWIND_SECTION_NAME
 	unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
 #endif
+	markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
+	markersdataindex = find_sec(hdr, sechdrs, secstrings, "__markers_data");
+	markersstringsindex = find_sec(hdr, sechdrs, secstrings,
+				"__markers_strings");
 
 	/* Don't keep modinfo section */
 	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1667,6 +1902,22 @@ static struct module *load_module(void __user *umod,
 #endif
 	if (unwindex)
 		sechdrs[unwindex].sh_flags |= SHF_ALLOC;
+#ifdef CONFIG_MARKERS
+	if (markersindex)
+		sechdrs[markersindex].sh_flags |= SHF_ALLOC;
+	if (markersdataindex)
+		sechdrs[markersdataindex].sh_flags |= SHF_ALLOC;
+	if (markersstringsindex)
+		sechdrs[markersstringsindex].sh_flags |= SHF_ALLOC;
+#else
+	if (markersindex)
+		sechdrs[markersindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+	if (markersdataindex)
+		sechdrs[markersdataindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+	if (markersstringsindex)
+		sechdrs[markersstringsindex].sh_flags
+					&= ~(unsigned long)SHF_ALLOC;
+#endif
 
 	/* Check module struct version now, before we try to use module. */
 	if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1803,6 +2054,11 @@ static struct module *load_module(void __user *umod,
 	mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
 	if (gplfuturecrcindex)
 		mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
+	if (markersindex) {
+		mod->markers = (void *)sechdrs[markersindex].sh_addr;
+		mod->num_markers =
+			sechdrs[markersindex].sh_size / sizeof(*mod->markers);
+	}
 
 	mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
 	if (unusedcrcindex)
@@ -1916,6 +2172,8 @@ static struct module *load_module(void __user *umod,
 	/* Get rid of temporary copy */
 	vfree(hdr);
 
+	MARK(kernel_module_load, "%s", mod->name);
+
 	/* Done! */
 	return mod;
 
@@ -2243,6 +2501,26 @@ const struct seq_operations modules_op = {
 	.show	= m_show
 };
 
+void list_modules(void)
+{
+	/* Enumerate loaded modules */
+	struct list_head	*i;
+	struct module		*mod;
+	unsigned long refcount = 0;
+
+	mutex_lock(&module_mutex);
+	list_for_each(i, &modules) {
+		mod = list_entry(i, struct module, list);
+#ifdef CONFIG_MODULE_UNLOAD
+		refcount = local_read(&mod->ref[0].count);
+#endif //CONFIG_MODULE_UNLOAD
+		MARK(list_module, "%s %d %lu",
+				mod->name, mod->state, refcount);
+	}
+	mutex_unlock(&module_mutex);
+}
+EXPORT_SYMBOL_GPL(list_modules);
+
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr)
 {
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 31aa039..69376db 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -268,6 +268,7 @@ int swsusp_suspend(void)
 		return error;
 
 	local_irq_disable();
+	local_irq_disable_hw_cond();
 	/* At this point, device_suspend() has been called, but *not*
 	 * device_power_down(). We *must* device_power_down() now.
 	 * Otherwise, drivers for some devices (e.g. interrupt controllers)
@@ -289,6 +290,7 @@ int swsusp_suspend(void)
 	 */
 	device_power_up();
  Enable_irqs:
+	local_irq_enable_hw_cond();
 	local_irq_enable();
 	return error;
 }
@@ -298,6 +300,7 @@ int swsusp_resume(void)
 	int error;
 
 	local_irq_disable();
+	local_irq_disable_hw_cond();
 	/* NOTE:  device_power_down() is just a suspend() with irqs off;
 	 * it has no special "power things down" semantics
 	 */
@@ -324,6 +327,7 @@ int swsusp_resume(void)
 	restore_processor_state();
 	touch_softlockup_watchdog();
 	device_power_up();
+	local_irq_enable_hw_cond();
 	local_irq_enable();
 	return error;
 }
diff --git a/kernel/printk.c b/kernel/printk.c
index c770e1a..6757ba7 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -479,6 +479,41 @@ static int have_callable_console(void)
 	return 0;
 }
 
+#ifdef CONFIG_IPIPE
+
+static ipipe_spinlock_t __ipipe_printk_lock = IPIPE_SPIN_LOCK_UNLOCKED;
+
+static int __ipipe_printk_fill;
+
+static char __ipipe_printk_buf[__LOG_BUF_LEN];
+
+void __ipipe_flush_printk (unsigned virq, void *cookie)
+{
+	char *p = __ipipe_printk_buf;
+	int len, lmax, out = 0;
+	unsigned long flags;
+
+	goto start;
+
+	do {
+		spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+ start:
+		lmax = __ipipe_printk_fill;
+		while (out < lmax) {
+			len = strlen(p) + 1;
+			printk("%s",p);
+			p += len;
+			out += len;
+		}
+		spin_lock_irqsave(&__ipipe_printk_lock, flags);
+	}
+	while (__ipipe_printk_fill != lmax);
+
+	__ipipe_printk_fill = 0;
+
+	spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+}
+
 /**
  * printk - print a kernel message
  * @fmt: format string
@@ -501,15 +536,59 @@ static int have_callable_console(void)
 
 asmlinkage int printk(const char *fmt, ...)
 {
+	int r, fbytes, oldcount;
+    	unsigned long flags;
+	va_list args;
+	int cs = -1;
+
+	va_start(args, fmt);
+
+	if (test_bit(IPIPE_SPRINTK_FLAG,&ipipe_current_domain->flags) ||
+	    oops_in_progress)
+		cs = ipipe_disable_context_check(ipipe_processor_id());
+
+	if (ipipe_current_domain == ipipe_root_domain || cs != -1) {
+		r = vprintk(fmt, args);
+		if (cs != -1)
+			ipipe_restore_context_check(ipipe_processor_id(), cs);
+		goto out;
+	}
+
+	spin_lock_irqsave(&__ipipe_printk_lock, flags);
+
+	oldcount = __ipipe_printk_fill;
+	fbytes = __LOG_BUF_LEN - oldcount;
+
+	if (fbytes > 1)	{
+		r = vscnprintf(__ipipe_printk_buf + __ipipe_printk_fill,
+			       fbytes, fmt, args) + 1; /* account for the null byte */
+		__ipipe_printk_fill += r;
+	} else
+		r = 0;
+
+	spin_unlock_irqrestore(&__ipipe_printk_lock, flags);
+
+	if (oldcount == 0)
+		ipipe_trigger_irq(__ipipe_printk_virq);
+out:
+	va_end(args);
+
+	return r;
+}
+#else /* !CONFIG_IPIPE */
+asmlinkage int printk(const char *fmt, ...)
+{
 	va_list args;
 	int r;
 
 	va_start(args, fmt);
+	MARK(kernel_printk, "%p", __builtin_return_address(0));
 	r = vprintk(fmt, args);
 	va_end(args);
 
 	return r;
 }
+#endif /* CONFIG_IPIPE */
 
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int printk_cpu = UINT_MAX;
@@ -529,7 +608,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 		zap_locks();
 
 	/* This stops the holder of console_sem just where we want him */
-	local_irq_save(flags);
+	raw_local_irq_save(flags);
 	lockdep_off();
 	spin_lock(&logbuf_lock);
 	printk_cpu = smp_processor_id();
@@ -537,6 +616,29 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 	/* Emit the output into the temporary buffer */
 	printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 
+	if (printed_len > 0) {
+		unsigned int loglevel;
+		int mark_len;
+		const char *mark_buf;
+
+		if (printk_buf[0] == '<' && printk_buf[1] >='0' &&
+		   printk_buf[1] <= '7' && printk_buf[2] == '>') {
+			loglevel = printk_buf[1] - '0';
+			mark_buf = &printk_buf[3];
+			mark_len = printed_len-3;
+		} else {
+			loglevel = default_message_loglevel;
+			mark_buf = printk_buf;
+			mark_len = printed_len;
+		}
+		if (mark_buf[mark_len-1] == '\n')
+			mark_len--;
+		_MARK(_MF_DEFAULT & ~_MF_LOCKDEP, kernel_vprintk,
+			"%c %*:*v %p",
+			loglevel, sizeof(char), mark_len, mark_buf,
+			__builtin_return_address(0));
+	}
+
 	/*
 	 * Copy the output into log_buf.  If the caller didn't provide
 	 * appropriate log level tags, we insert them here
@@ -618,7 +720,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 			up(&console_sem);
 		}
 		lockdep_on();
-		local_irq_restore(flags);
+		raw_local_irq_restore(flags);
 	} else {
 		/*
 		 * Someone else owns the drivers.  We drop the spinlock, which
@@ -628,7 +730,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
 		printk_cpu = UINT_MAX;
 		spin_unlock(&logbuf_lock);
 		lockdep_on();
-		local_irq_restore(flags);
+		raw_local_irq_restore(flags);
 	}
 
 	preempt_enable();
diff --git a/kernel/relay.c b/kernel/relay.c
index 284e2e8..d277b0d 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -7,6 +7,8 @@
  * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
  *
  * Moved to kernel/relay.c by Paul Mundt, 2006.
+ * November 2006 - CPU hotplug support by Mathieu Desnoyers
+ * 	(mathieu.desnoyers@polymtl.ca)
  *
  * This file is released under the GPL.
  */
@@ -18,6 +20,11 @@
 #include <linux/relay.h>
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
+#include <linux/cpu.h>
+
+/* list of open channels, for cpu hotplug */
+static DEFINE_MUTEX(relay_channels_mutex);
+static LIST_HEAD(relay_channels);
 
 /*
  * close() vm_op implementation for relay file mapping.
@@ -187,6 +194,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
 			__free_page(buf->page_array[i]);
 		kfree(buf->page_array);
 	}
+	chan->buf[buf->cpu] = NULL;
 	kfree(buf->padding);
 	kfree(buf);
 	kref_put(&chan->kref, relay_destroy_channel);
@@ -362,58 +370,76 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
 void relay_reset(struct rchan *chan)
 {
 	unsigned int i;
-	struct rchan_buf *prev = NULL;
 
 	if (!chan)
 		return;
 
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!chan->buf[i] || chan->buf[i] == prev)
-			break;
-		__relay_reset(chan->buf[i], 0);
-		prev = chan->buf[i];
+ 	if (chan->is_global && chan->buf[0]) {
+		__relay_reset(chan->buf[0], 0);
+		return;
 	}
+
+	mutex_lock(&relay_channels_mutex);
+	for_each_online_cpu(i)
+		if (chan->buf[i])
+			__relay_reset(chan->buf[i], 0);
+	mutex_unlock(&relay_channels_mutex);
 }
 EXPORT_SYMBOL_GPL(relay_reset);
 
 /*
  *	relay_open_buf - create a new relay channel buffer
  *
- *	Internal - used by relay_open().
+ *	used by relay_open() and CPU hotplug.
  */
-static struct rchan_buf *relay_open_buf(struct rchan *chan,
-					const char *filename,
-					struct dentry *parent,
-					int *is_global)
+static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu)
 {
-	struct rchan_buf *buf;
+ 	struct rchan_buf *buf = NULL;
 	struct dentry *dentry;
+ 	char *tmpname;
 
-	if (*is_global)
+ 	if (chan->is_global)
 		return chan->buf[0];
 
+	tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL);
+ 	if (!tmpname)
+ 		goto end;
+ 	snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu);
+
 	buf = relay_create_buf(chan);
 	if (!buf)
-		return NULL;
+ 		goto free_name;
+
+ 	buf->cpu = cpu;
+ 	__relay_reset(buf, 1);
 
 	/* Create file in fs */
-	dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR,
-					   buf, is_global);
-	if (!dentry) {
-		relay_destroy_buf(buf);
-		return NULL;
-	}
+ 	dentry = chan->cb->create_buf_file(tmpname, chan->parent, S_IRUSR,
+ 					   buf, &chan->is_global);
+ 	if (!dentry)
+ 		goto free_buf;
 
 	buf->dentry = dentry;
-	__relay_reset(buf, 1);
 
+ 	if(chan->is_global) {
+ 		chan->buf[0] = buf;
+ 		buf->cpu = 0;
+  	}
+
+ 	goto free_name;
+
+free_buf:
+ 	relay_destroy_buf(buf);
+free_name:
+ 	kfree(tmpname);
+end:
 	return buf;
 }
 
 /**
  *	relay_close_buf - close a channel buffer
  *	@buf: channel buffer
- *
+ *	
  *	Marks the buffer finalized and restores the default callbacks.
  *	The channel buffer and channel buffer data structure are then freed
  *	automatically when the last reference is given up.
@@ -448,12 +474,54 @@ static void setup_callbacks(struct rchan *chan,
 }
 
 /**
+ *
+ * 	relay_hotcpu_callback - CPU hotplug callback
+ * 	@nb: notifier block
+ * 	@action: hotplug action to take
+ * 	@hcpu: CPU number
+ *
+ * 	Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD)
+ */
+static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
+				unsigned long action,
+				void *hcpu)
+{
+	unsigned int hotcpu = (unsigned long)hcpu;
+	struct rchan *chan;
+
+	switch(action) {
+	case CPU_UP_PREPARE:
+		mutex_lock(&relay_channels_mutex);
+		list_for_each_entry(chan, &relay_channels, list) {
+			if (chan->buf[hotcpu])
+				continue;
+			chan->buf[hotcpu] = relay_open_buf(chan, hotcpu);
+			if(!chan->buf[hotcpu]) {
+				printk(KERN_ERR
+					"relay_hotcpu_callback: cpu %d buffer "
+					"creation failed\n", hotcpu);
+				mutex_unlock(&relay_channels_mutex);
+				return NOTIFY_BAD;
+			}
+		}
+		mutex_unlock(&relay_channels_mutex);
+		break;
+	case CPU_DEAD:
+		/* No need to flush the cpu : will be flushed upon
+		 * final relay_flush() call. */
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+/**
  *	relay_open - create a new relay channel
  *	@base_filename: base name of files to create
  *	@parent: dentry of parent directory, %NULL for root directory
  *	@subbuf_size: size of sub-buffers
  *	@n_subbufs: number of sub-buffers
  *	@cb: client callback functions
+ *	@private_data: user-defined data
  *
  *	Returns channel pointer if successful, %NULL otherwise.
  *
@@ -466,13 +534,11 @@ struct rchan *relay_open(const char *base_filename,
 			 struct dentry *parent,
 			 size_t subbuf_size,
 			 size_t n_subbufs,
-			 struct rchan_callbacks *cb)
+			 struct rchan_callbacks *cb,
+			 void *private_data)
 {
 	unsigned int i;
 	struct rchan *chan;
-	char *tmpname;
-	int is_global = 0;
-
 	if (!base_filename)
 		return NULL;
 
@@ -487,38 +553,32 @@ struct rchan *relay_open(const char *base_filename,
 	chan->n_subbufs = n_subbufs;
 	chan->subbuf_size = subbuf_size;
 	chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs);
+	chan->parent = parent;
+	chan->private_data = private_data;
+	strlcpy(chan->base_filename, base_filename, NAME_MAX);
 	setup_callbacks(chan, cb);
 	kref_init(&chan->kref);
 
-	tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL);
-	if (!tmpname)
-		goto free_chan;
-
+	mutex_lock(&relay_channels_mutex);
 	for_each_online_cpu(i) {
-		sprintf(tmpname, "%s%d", base_filename, i);
-		chan->buf[i] = relay_open_buf(chan, tmpname, parent,
-					      &is_global);
+		chan->buf[i] = relay_open_buf(chan, i);
 		if (!chan->buf[i])
 			goto free_bufs;
-
-		chan->buf[i]->cpu = i;
 	}
+	list_add(&chan->list, &relay_channels);
+	mutex_unlock(&relay_channels_mutex);
 
-	kfree(tmpname);
 	return chan;
 
 free_bufs:
-	for (i = 0; i < NR_CPUS; i++) {
+	for_each_online_cpu(i) {
 		if (!chan->buf[i])
 			break;
 		relay_close_buf(chan->buf[i]);
-		if (is_global)
-			break;
 	}
-	kfree(tmpname);
 
-free_chan:
 	kref_put(&chan->kref, relay_destroy_channel);
+	mutex_unlock(&relay_channels_mutex);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(relay_open);
@@ -619,24 +679,26 @@ EXPORT_SYMBOL_GPL(relay_subbufs_consumed);
 void relay_close(struct rchan *chan)
 {
 	unsigned int i;
-	struct rchan_buf *prev = NULL;
 
 	if (!chan)
 		return;
 
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!chan->buf[i] || chan->buf[i] == prev)
-			break;
-		relay_close_buf(chan->buf[i]);
-		prev = chan->buf[i];
-	}
+	mutex_lock(&relay_channels_mutex);
+	if (chan->is_global && chan->buf[0])
+		relay_close_buf(chan->buf[0]);
+	else
+		for_each_possible_cpu(i)
+			if (chan->buf[i])
+				relay_close_buf(chan->buf[i]);
 
 	if (chan->last_toobig)
 		printk(KERN_WARNING "relay: one or more items not logged "
 		       "[item size (%Zd) > sub-buffer size (%Zd)]\n",
 		       chan->last_toobig, chan->subbuf_size);
 
+	list_del(&chan->list);
 	kref_put(&chan->kref, relay_destroy_channel);
+	mutex_unlock(&relay_channels_mutex);	
 }
 EXPORT_SYMBOL_GPL(relay_close);
 
@@ -649,17 +711,20 @@ EXPORT_SYMBOL_GPL(relay_close);
 void relay_flush(struct rchan *chan)
 {
 	unsigned int i;
-	struct rchan_buf *prev = NULL;
 
 	if (!chan)
 		return;
 
-	for (i = 0; i < NR_CPUS; i++) {
-		if (!chan->buf[i] || chan->buf[i] == prev)
-			break;
-		relay_switch_subbuf(chan->buf[i], 0);
-		prev = chan->buf[i];
+	if (chan->is_global && chan->buf[0]) {
+		relay_switch_subbuf(chan->buf[0], 0);
+		return;
 	}
+
+	mutex_lock(&relay_channels_mutex);
+	for_each_possible_cpu(i)
+		if (chan->buf[i])
+			relay_switch_subbuf(chan->buf[i], 0);
+	mutex_unlock(&relay_channels_mutex);
 }
 EXPORT_SYMBOL_GPL(relay_flush);
 
@@ -1022,3 +1087,12 @@ const struct file_operations relay_file_operations = {
 	.sendfile       = relay_file_sendfile,
 };
 EXPORT_SYMBOL_GPL(relay_file_operations);
+
+static __init int relay_init(void)
+{
+
+	hotcpu_notifier(relay_hotcpu_callback, 0);
+	return 0;
+}
+
+module_init(relay_init);
diff --git a/kernel/sched.c b/kernel/sched.c
index cca93cc..80c714c 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1115,6 +1115,7 @@ void wait_task_inactive(struct task_struct *p)
 
 repeat:
 	rq = task_rq_lock(p, &flags);
+	MARK(kernel_sched_wait_task, "%d %ld", p->pid, p->state);
 	/* Must be off runqueue entirely, not preempted. */
 	if (unlikely(p->array || task_running(rq, p))) {
 		/* If it's preempted, we yield.  It could be a while. */
@@ -1408,8 +1409,9 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
 #endif
 
 	rq = task_rq_lock(p, &flags);
+	MARK(kernel_sched_try_wakeup, "%d %ld", p->pid, p->state);
 	old_state = p->state;
-	if (!(old_state & state))
+	if (!(old_state & state) || (old_state & (TASK_NOWAKEUP|TASK_ATOMICSWITCH)))
 		goto out;
 
 	if (p->array)
@@ -1648,6 +1650,7 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
 	int this_cpu, cpu;
 
 	rq = task_rq_lock(p, &flags);
+	MARK(kernel_sched_wakeup_new_task, "%d %ld", p->pid, p->state);
 	BUG_ON(p->state != TASK_RUNNING);
 	this_cpu = smp_processor_id();
 	cpu = task_cpu(p);
@@ -1830,6 +1833,8 @@ asmlinkage void schedule_tail(struct task_struct *prev)
 #endif
 	if (current->set_child_tid)
 		put_user(current->pid, current->set_child_tid);
+
+	ipipe_init_notify(current);
 }
 
 /*
@@ -2034,6 +2039,8 @@ static void sched_migrate_task(struct task_struct *p, int dest_cpu)
 	    || unlikely(cpu_is_offline(dest_cpu)))
 		goto out;
 
+	MARK(kernel_sched_migrate_task, "%d %ld %d",
+		p->pid, p->state, dest_cpu);
 	/* force the process onto the specified CPU */
 	if (migrate_task(p, dest_cpu, &req)) {
 		/* Need to wait for migration thread (might exit: take ref). */
@@ -3420,12 +3427,15 @@ asmlinkage void __sched schedule(void)
 	long *switch_count;
 	struct rq *rq;
 
+	ipipe_check_context(ipipe_root_domain);
+
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
 	 * schedule() atomically, we ignore that path for now.
 	 * Otherwise, whine if we are scheduling when we should not be.
 	 */
-	if (unlikely(in_atomic() && !current->exit_state)) {
+	if (unlikely(!(current->state & TASK_ATOMICSWITCH) && in_atomic() &&
+			!current->exit_state)) {
 		printk(KERN_ERR "BUG: scheduling while atomic: "
 			"%s/0x%08x/%d\n",
 			current->comm, preempt_count(), current->pid);
@@ -3436,8 +3446,16 @@ asmlinkage void __sched schedule(void)
 	}
 	profile_hit(SCHED_PROFILING, __builtin_return_address(0));
 
+	if (unlikely(current->state & TASK_ATOMICSWITCH)) {
+#ifndef CONFIG_IPIPE_DELAYED_ATOMICSW
+		current->state &= ~TASK_ATOMICSWITCH;
+#endif
+		goto need_resched_nodisable;
+	}
+
 need_resched:
 	preempt_disable();
+need_resched_nodisable:
 	prev = current;
 	release_kernel_lock(prev);
 need_resched_nonpreemptible:
@@ -3553,22 +3571,31 @@ switch_tasks:
 		++*switch_count;
 
 		prepare_task_switch(rq, next);
+		MARK(kernel_sched_schedule, "%d %d %ld", 
+			prev->pid, next->pid, prev->state);
 		prev = context_switch(rq, prev, next);
 		barrier();
+#ifdef CONFIG_IPIPE_DELAYED_ATOMICSW
+		current->state &= ~TASK_ATOMICSWITCH;
+#endif
+ 		if (task_hijacked(prev))
+			return;
 		/*
 		 * this_rq must be evaluated again because prev may have moved
 		 * CPUs since it called schedule(), thus the 'rq' on its stack
 		 * frame will be invalid.
 		 */
 		finish_task_switch(this_rq(), prev);
-	} else
+	} else {
+		prev->state &= ~TASK_ATOMICSWITCH;
 		spin_unlock_irq(&rq->lock);
+	}
 
 	prev = current;
 	if (unlikely(reacquire_kernel_lock(prev) < 0))
 		goto need_resched_nonpreemptible;
 	preempt_enable_no_resched();
-	if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
+	if (unlikely(test_thread_flag(TIF_NEED_RESCHED) && ipipe_root_domain_p))
 		goto need_resched;
 }
 EXPORT_SYMBOL(schedule);
@@ -3586,6 +3613,7 @@ asmlinkage void __sched preempt_schedule(void)
 	struct task_struct *task = current;
 	int saved_lock_depth;
 #endif
+	ipipe_check_context(ipipe_root_domain);
 	/*
 	 * If there is a non-zero preempt_count or interrupts are disabled,
 	 * we do not want to preempt the current task.  Just return..
@@ -4284,6 +4312,7 @@ recheck:
 		deactivate_task(p, rq);
 	oldprio = p->prio;
 	__setscheduler(p, policy, param->sched_priority);
+	ipipe_setsched_notify(p);
 	if (array) {
 		__activate_task(p, rq);
 		/*
@@ -7057,3 +7086,50 @@ void set_curr_task(int cpu, struct task_struct *p)
 }
 
 #endif
+
+#ifdef CONFIG_IPIPE
+
+int ipipe_setscheduler_root (struct task_struct *p, int policy, int prio)
+{
+	struct prio_array *array;
+	unsigned long flags;
+	struct rq *rq;
+	int oldprio;
+
+	rq = task_rq_lock(p, &flags);
+	array = p->array;
+	if (array)
+		deactivate_task(p, rq);
+	oldprio = p->prio;
+	__setscheduler(p, policy, prio);
+	if (array) {
+		__activate_task(p, rq);
+		if (task_running(rq, p)) {
+			if (p->prio > oldprio)
+				resched_task(rq->curr);
+		} else if (TASK_PREEMPTS_CURR(p, rq))
+			resched_task(rq->curr);
+	}
+	task_rq_unlock(rq, &flags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ipipe_setscheduler_root);
+
+int ipipe_reenter_root (struct task_struct *prev, int policy, int prio)
+{
+	finish_task_switch(this_rq(), prev);
+	if (reacquire_kernel_lock(current) < 0)
+		;
+	preempt_enable_no_resched();
+
+	if (current->policy != policy || current->rt_priority != prio)
+		return ipipe_setscheduler_root(current,policy,prio);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(ipipe_reenter_root);
+
+#endif /* CONFIG_IPIPE */
diff --git a/kernel/signal.c b/kernel/signal.c
index 5630255..0490605 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -508,6 +508,7 @@ void signal_wake_up(struct task_struct *t, int resume)
 	unsigned int mask;
 
 	set_tsk_thread_flag(t, TIF_SIGPENDING);
+	ipipe_sigwake_notify(t); /* TIF_SIGPENDING must be set first. */
 
 	/*
 	 * For SIGKILL, we want to wake it up in the stopped/traced case.
@@ -784,6 +785,8 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 	if (sig_ignored(t, sig))
 		goto out;
 
+	MARK(kernel_process_signal, "%d %d", t->pid, sig);
+
 	/* Support queueing exactly one non-rt signal, so that we
 	   can get more detailed information about the cause of
 	   the signal. */
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 918e52d..fe34d03 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -227,7 +227,15 @@ restart:
 
 	do {
 		if (pending & 1) {
+			MARK(kernel_softirq_entry, "%lu",
+				((unsigned long)h
+					- (unsigned long)softirq_vec)
+					/ sizeof(*h));
 			h->action(h);
+			MARK(kernel_softirq_exit, "%lu",
+				((unsigned long)h
+					- (unsigned long)softirq_vec)
+					/ sizeof(*h));
 			rcu_bh_qsctr_inc(cpu);
 		}
 		h++;
@@ -384,7 +392,11 @@ static void tasklet_action(struct softirq_action *a)
 			if (!atomic_read(&t->count)) {
 				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
 					BUG();
+				MARK(kernel_tasklet_low_entry, "%p %lu",
+						t->func, t->data);
 				t->func(t->data);
+				MARK(kernel_tasklet_low_exit, "%p %lu",
+						t->func, t->data);
 				tasklet_unlock(t);
 				continue;
 			}
@@ -417,7 +429,11 @@ static void tasklet_hi_action(struct softirq_action *a)
 			if (!atomic_read(&t->count)) {
 				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
 					BUG();
+				MARK(kernel_tasklet_high_entry, "%p %lu",
+						t->func, t->data);
 				t->func(t->data);
+				MARK(kernel_tasklet_high_exit, "%p %lu",
+						t->func, t->data);
 				tasklet_unlock(t);
 				continue;
 			}
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
index 2c6c2bf..14fda25 100644
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -88,7 +88,7 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
 	 * _raw_spin_lock_flags() code, because lockdep assumes
 	 * that interrupts are not re-enabled during lock-acquire:
 	 */
-#ifdef CONFIG_PROVE_LOCKING
+#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_IPIPE)
 	_raw_spin_lock(lock);
 #else
 	_raw_spin_lock_flags(lock, &flags);
@@ -305,7 +305,7 @@ unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclas
 	 * _raw_spin_lock_flags() code, because lockdep assumes
 	 * that interrupts are not re-enabled during lock-acquire:
 	 */
-#ifdef CONFIG_PROVE_SPIN_LOCKING
+#if defined(CONFIG_PROVE_SPIN_LOCKING) || defined(CONFIG_IPIPE)
 	_raw_spin_lock(lock);
 #else
 	_raw_spin_lock_flags(lock, &flags);
diff --git a/kernel/sys.c b/kernel/sys.c
index 6e2101d..70dd5f2 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -227,9 +227,11 @@ int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
 {
 	int ret;
 
-	rcu_read_lock();
+	if (ipipe_root_domain_p)
+		rcu_read_lock();
 	ret = notifier_call_chain(&nh->head, val, v);
-	rcu_read_unlock();
+	if (ipipe_root_domain_p)
+		rcu_read_unlock();
 	return ret;
 }
 
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index d7306d0..4dd81bc 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -112,6 +112,8 @@ cond_syscall(sys_vm86old);
 cond_syscall(sys_vm86);
 cond_syscall(compat_sys_ipc);
 cond_syscall(compat_sys_sysctl);
+cond_syscall(sys_ltt_trace_generic);
+cond_syscall(sys_ltt_register_generic);
 
 /* arch-specific weak syscall entries */
 cond_syscall(sys_pciconfig_read);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 22504af..dda1e21 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -28,6 +28,7 @@
 #include <linux/sysdev.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 
 /* XXX - Would like a better way for initializing curr_clocksource */
 extern struct clocksource clocksource_jiffies;
diff --git a/kernel/timer.c b/kernel/timer.c
index c2a8ccf..38d19aa 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -40,6 +40,7 @@
 #include <asm/div64.h>
 #include <asm/timex.h>
 #include <asm/io.h>
+#include <asm/irq_regs.h>
 
 u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
 
@@ -256,6 +257,8 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
 		i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
 		vec = base->tv5.vec + i;
 	}
+	MARK(kernel_timer_set, "%lu %p %lu",
+		expires, timer->function, timer->data);
 	/*
 	 * Timers are FIFO:
 	 */
@@ -1209,6 +1212,12 @@ void do_timer(unsigned long ticks)
 {
 	jiffies_64 += ticks;
 	update_times(ticks);
+	MARK(kernel_timer_update_time,
+	"%8b %*.*r %*.*r",
+		jiffies_64,
+		sizeof(xtime), __alignof__(xtime), &xtime,
+		sizeof(wall_to_monotonic), __alignof__(wall_to_monotonic),
+		&wall_to_monotonic);
 }
 
 #ifdef __ARCH_WANT_SYS_ALARM
@@ -1290,7 +1299,9 @@ asmlinkage long sys_getegid(void)
 
 static void process_timeout(unsigned long __data)
 {
-	wake_up_process((struct task_struct *)__data);
+	struct task_struct *task = (struct task_struct *)__data;
+	MARK(kernel_timer_timeout, "%d", task->pid);
+	wake_up_process(task);
 }
 
 /**
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 5c26818..36cd9ec 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -71,6 +71,8 @@ config HEADERS_CHECK
 	  exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
 	  your build tree), to make sure they're suitable.
 
+source "kernel/ipipe/Kconfig.debug"
+
 config DEBUG_KERNEL
 	bool "Kernel debugging"
 	help
diff --git a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c
index a2055bc..a49201f 100644
--- a/lib/bust_spinlocks.c
+++ b/lib/bust_spinlocks.c
@@ -12,14 +12,19 @@
 #include <linux/tty.h>
 #include <linux/wait.h>
 #include <linux/vt_kern.h>
+#include <linux/ipipe_trace.h>
 
 
 void bust_spinlocks(int yes)
 {
 	if (yes) {
+		ipipe_trace_panic_freeze();
 		oops_in_progress = 1;
 	} else {
 		int loglevel_save = console_loglevel;
+
+		ipipe_trace_panic_dump();
+
 #ifdef CONFIG_VT
 		unblank_screen();
 #endif
diff --git a/lib/ioremap.c b/lib/ioremap.c
index a9e4415..52d1787 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -84,8 +84,8 @@ int ioremap_page_range(unsigned long addr,
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
-
-	flush_cache_vmap(start, end);
+	__ipipe_pin_range_globally(start, end);
+ 	flush_cache_vmap(start, end);
 
 	return err;
 }
diff --git a/lib/smp_processor_id.c b/lib/smp_processor_id.c
index eddc9b3..66302ec 100644
--- a/lib/smp_processor_id.c
+++ b/lib/smp_processor_id.c
@@ -13,10 +13,13 @@ unsigned int debug_smp_processor_id(void)
 	int this_cpu = raw_smp_processor_id();
 	cpumask_t this_mask;
 
+	if (!ipipe_root_domain_p)
+		goto out;
+
 	if (likely(preempt_count))
 		goto out;
 
-	if (irqs_disabled())
+	if (irqs_disabled() || irqs_disabled_hw())
 		goto out;
 
 	/*
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 479fd46..5e135ef 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -133,6 +133,8 @@ void _raw_spin_lock(spinlock_t *lock)
 	debug_spin_lock_after(lock);
 }
 
+EXPORT_SYMBOL(_raw_spin_lock);
+
 int _raw_spin_trylock(spinlock_t *lock)
 {
 	int ret = __raw_spin_trylock(&lock->raw_lock);
@@ -148,12 +150,16 @@ int _raw_spin_trylock(spinlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_spin_trylock);
+
 void _raw_spin_unlock(spinlock_t *lock)
 {
 	debug_spin_unlock(lock);
 	__raw_spin_unlock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_spin_unlock);
+
 static void rwlock_bug(rwlock_t *lock, const char *msg)
 {
 	if (!debug_locks_off())
@@ -199,6 +205,8 @@ void _raw_read_lock(rwlock_t *lock)
 	__raw_read_lock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_read_lock);
+
 int _raw_read_trylock(rwlock_t *lock)
 {
 	int ret = __raw_read_trylock(&lock->raw_lock);
@@ -212,12 +220,16 @@ int _raw_read_trylock(rwlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_read_trylock);
+
 void _raw_read_unlock(rwlock_t *lock)
 {
 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
 	__raw_read_unlock(&lock->raw_lock);
 }
 
+EXPORT_SYMBOL(_raw_read_unlock);
+
 static inline void debug_write_lock_before(rwlock_t *lock)
 {
 	RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic");
@@ -275,6 +287,8 @@ void _raw_write_lock(rwlock_t *lock)
 	debug_write_lock_after(lock);
 }
 
+EXPORT_SYMBOL(_raw_write_lock);
+
 int _raw_write_trylock(rwlock_t *lock)
 {
 	int ret = __raw_write_trylock(&lock->raw_lock);
@@ -290,8 +304,12 @@ int _raw_write_trylock(rwlock_t *lock)
 	return ret;
 }
 
+EXPORT_SYMBOL(_raw_write_trylock);
+
 void _raw_write_unlock(rwlock_t *lock)
 {
 	debug_write_unlock(lock);
 	__raw_write_unlock(&lock->raw_lock);
 }
+
+EXPORT_SYMBOL(_raw_write_unlock);
diff --git a/ltt/Kconfig b/ltt/Kconfig
new file mode 100644
index 0000000..afe6f76
--- /dev/null
+++ b/ltt/Kconfig
@@ -0,0 +1,327 @@
+config LTT
+	bool "Linux Trace Toolkit Instrumentation Support"
+	depends on EXPERIMENTAL
+	depends on MARKERS
+	select LTT_HEARTBEAT if MIPS
+	select LTT_SYNTHETIC_TSC if MIPS
+	default n
+	help
+	  It is possible for the kernel to log important events to a trace
+	  facility. Doing so, enables the use of the generated traces in order
+	  to reconstruct the dynamic behavior of the kernel, and hence the
+	  whole system.
+
+	  The tracing process contains 4 parts :
+	      1) The logging of events by key parts of the kernel.
+	      2) The tracer that keeps the events in a data buffer (uses
+	         relayfs).
+	      3) A trace daemon that interacts with the tracer and is
+	         notified every time there is a certain quantity of data to
+	         read from the tracer.
+	      4) A trace event data decoder that reads the accumulated data
+	         and formats it in a human-readable format.
+
+	  If you say Y, the first component will be built into the kernel.
+
+	  For more information on kernel tracing, the trace daemon or the event
+	  decoder, please check the following address :
+	       http://www.opersys.com/ltt
+	  See also the experimental page of the project :
+	       http://ltt.polymtl.ca
+
+config LTT_TRACER
+	tristate "Linux Trace Toolkit Tracer"
+	depends on LTT
+	default y
+	help
+	  If you enable this option, the Linux Trace Toolkit Tracer will be
+	  either built in the kernel or as module.
+
+	  Critical parts of the kernel will call upon the kernel tracing
+	  function. The data is then recorded by the tracer if a trace daemon
+	  is running in user-space and has issued a "start" command.
+
+	  For more information on kernel tracing, the trace daemon or the event
+	  decoder, please check the following address :
+	       http://www.opersys.com/ltt
+	  See also the experimental page of the project :
+	       http://ltt.polymtl.ca
+
+config LTT_RELAY
+	tristate "Linux Trace Toolkit Relay+DebugFS Support"
+	select RELAY
+	select DEBUG_FS
+	depends on LTT_TRACER
+	default y
+	help
+	  Support using relay and debugfs to log the data obtained through LTT.
+
+	  If you don't have special hardware, you almost certainly want
+	  to say Y here.
+
+config LTT_SERIALIZE
+	tristate "Linux Trace Toolkit Serializer"
+	depends on LTT_TRACER
+	default y
+	help
+	  Library for serializing information from format string and argument
+	  list to the trace buffers.
+
+config LTT_ALIGNMENT
+	bool "Align Linux Trace Toolkit Traces"
+	depends on LTT
+	default y
+	help
+	  This option enables dynamic alignment of data in buffers. The
+	  alignment is made on the smallest size between architecture size
+	  and the size of the value to be written.
+
+	  Dynamically calculating the offset of the data has a performance cost,
+	  but it is more efficient on some architectures (especially 64 bits) to
+	  align data than to write it unaligned.
+
+config LTT_HEARTBEAT
+	bool "Activate Linux Trace Toolkit Heartbeat Timer"
+	depends on LTT
+	default n
+	help
+	  The Linux Trace Toolkit Heartbeat Timer fires at an interval small
+	  enough to guarantee that the 32 bits truncated TSC won't overflow
+	  between two timer execution.
+
+config LTT_HEARTBEAT_EVENT
+	bool "Write heartbeat event to shrink traces (EXPERIMENTAL)"
+	depends on LTT_HEARTBEAT
+	depends on EXPERIMENTAL
+	default n
+	help
+	  This option makes the heartbeat timer write an event in each tracefile
+	  at an interval that is one tenth of the time it takes to overflow 32
+	  bits at your CPU frequency.
+
+	  If this option is not enabled, 64 bits fields must be used in each
+	  event header to save the full TSC : it can make traces about 1/10
+	  bigger. It is suggested that you enable this option to make more
+	  compact traces.
+
+	  Note : it is currently broken with CPU hotplug and does not support
+	  trace stop / restart correctly.
+
+config LTT_SYNTHETIC_TSC
+	bool "Keep a synthetic cpu timestamp counter"
+	depends on LTT_HEARTBEAT
+	default n
+	help
+	  This option is only useful on archtecture lacking a 64 bits timestamp
+	  counter : it generates a "synthetic" 64 bits timestamp by updating
+	  the 32 MSB at each heartbeat atomically. See kernel/ltt-heartbeat.c
+	  for details.
+
+config LTT_TEST_TSC
+	bool "Test TSC synchronicity"
+	depends on LTT
+	default y
+	depends on X86_32 || X86_64
+	help
+	  On i386 and x86_64, test TSC synchronicity. Fall back on a TSC|logical
+	  clock scheme where CPU with TSCs lagging behind use the logical
+	  relative to the highest TSC count read.
+
+config LTT_USERSPACE_GENERIC
+	bool "Allow tracing from userspace"
+	depends on LTT
+	default y
+	help
+	  This options allows processes to trace through the ltt_trace_generic
+	  system call after they have registered their facilities with
+	  ltt_register_generic.
+
+config LTT_NETLINK_CONTROL
+	tristate "Linux Trace Toolkit Netlink Controller"
+	depends on LTT_TRACER
+	select NET
+	default m
+	help
+	  If you enable this option, the Linux Trace Toolkit Netlink Controller
+	  will be either built in the kernel of as module.
+
+config LTT_STATEDUMP
+	tristate "Linux Trace Toolkit State Dump"
+	depends on LTT_TRACER
+	default m
+	help
+	  If you enable this option, the Linux Trace Toolkit State Dump will
+	  be either built in the kernel of as module.
+
+	  This module saves the state of the running kernel at trace start
+	  into the trace buffers along with the ongoing tracing information.
+
+menu "Probes"
+	depends on LTT && MARKERS
+
+config LTT_PROBE_CORE
+	tristate "Linux Trace Toolkit Core Probe"
+	depends on LTT_SERIALIZE
+	depends on LTT_TRACER
+	depends on CRC32
+	default m
+	help
+	  Probes the core LTT events, required to have the event descriptions
+	  and heartbeat events.
+
+config LTT_PROBE_FS
+	tristate "Linux Trace Toolkit File System Probe"
+	depends on LTT_SERIALIZE
+	depends on CRC32
+	default m
+	help
+	  Activate per facilities LTT probes. This is the dynamic mechanism
+	  where the data gathering is. Probes connect to markers when their
+	  module is loaded.
+
+	  Probe file system events. It instruments the file operations and
+	  dumps the beginning of data sent through read and write system calls.
+
+config LTT_PROBE_KERNEL
+	tristate "Linux Trace Toolkit Kernel Probe"
+	depends on LTT_SERIALIZE
+	depends on CRC32
+	default m
+	help
+	  LTT Kernel probe. Contains event definition for tasklet, irq,
+	  soft irq, timer and scheduling events.
+
+config LTT_PROBE_ARCH
+	tristate "Linux Trace Toolkit Architecture Specific Probe"
+	depends on LTT_SERIALIZE
+	depends on X86_32 || ARM || MIPS || PPC || X86_64
+	depends on CRC32
+	default m
+	help
+	  LTT Arch Probe. Contains event definition specific to each
+	  architecture. (system calls, traps, ...)
+
+config LTT_PROBE_MM
+	tristate "Linux Trace Toolkit Memory Probe"
+	depends on LTT_SERIALIZE
+	depends on CRC32
+	default m
+	help
+	  Activate per facilities LTT probes. This is the dynamic mechanism
+	  where the data gathering is. Probes connect to markers when their
+	  module is loaded.
+
+	  LTT Memory probe.
+
+config LTT_PROBE_NET
+	tristate "Linux Trace Toolkit Network Probe"
+	depends on LTT_SERIALIZE
+	depends on CRC32
+	default m
+	help
+	  Activate per facilities LTT probes. This is the dynamic mechanism
+	  where the data gathering is. Probes connect to markers when their
+	  module is loaded.
+
+	  LTT Network probe.
+
+config LTT_PROBE_LIST
+	tristate "Linux Trace Toolkit system listing probe"
+	depends on LTT_SERIALIZE
+	depends on LTT_STATEDUMP
+	depends on CRC32
+	default m
+	help
+	  System listing probe. Contains events for dumping kernel
+	  state at the beginning of a trace.
+
+config LTT_PROBE_LOCKING
+	tristate "Linux Trace Toolkit locking"
+	depends on LTT_SERIALIZE
+	depends on X86_32 || MIPS || S390 || SUPERH || SPARC64 || UML || X86_64
+	depends on CRC32
+	select TRACE_IRQFLAGS
+	select DEBUG_KERNEL
+	select TRACE_IRQFLAGS_SUPPORT
+	select STACKTRACE_SUPPORT
+	select LOCKDEP_SUPPORT
+	select LOCKDEP
+	select DEBUG_LOCK_ALLOC
+	default m
+	help
+	  LTT locking probe. Traces currently only interrupt save/restore and
+	  disable/enable. Currently only for i386, MIPS, S390, SH, Sparc64, UML
+	  and x86_64. Will trace events from lockdep when connected with a
+	  probe.
+
+config LTT_PROBE_STACK
+	tristate "Sample process or kernel stacks (EXPERIMENTAL)"
+	depends on LTT_SERIALIZE
+	depends on X86 || X86_64
+	depends on CRC32
+	default n
+	help
+	  Get complete process and/or kernel stack (architecture specific)
+
+config LTT_PROBE_XENOMAI
+	tristate "Linux Trace Toolkit Xenomai Probe"
+	depends on LTT_SERIALIZE
+	depends on CRC32
+	default m
+	help
+	  Activate per facilities LTT probes. This is the dynamic mechanism
+	  where the data gathering is. Probes connect to markers when their
+	  module is loaded.
+
+	  LTT Xenomai probe.
+
+config LTT_PROCESS_STACK
+	bool "Get complete process stack"
+	depends on LTT_PROBE_STACK
+	depends on X86
+	depends on CRC32
+	default n
+	help
+	  Get complete process stack.
+
+	  It has three limitations : it only considers functions in the loaded
+	  executable (not libraries) to be actual function pointers.
+	  Furthermore, it will dump the stack of many threads at once for
+	  multithreaded processes (it is protected from races between threads
+	  though). It can also believe that arbritrary data on the stack
+	  "looks like" a function pointer.
+
+config LTT_PROCESS_MAX_FUNCTION_STACK
+	int "Maximum number of longs on the stack between functions"
+	depends on LTT_PROCESS_STACK
+	default 100
+	help
+	  Maximum threshold over which, if we do not find a function pointer on
+	  the process stack, we stop dumping the pointers on the stack.
+
+config LTT_PROCESS_MAX_STACK_LEN
+	int "Maximum number of longs on the stack to read"
+	depends on LTT_PROCESS_STACK
+	default 250
+	help
+	  Maximum threshold of stack size over which we stop looking for
+	  function pointers.
+
+config LTT_KERNEL_STACK
+	bool "Get complete kernel stack"
+	depends on LTT_PROBE_STACK
+	default n
+	help
+	  Get complete kernel stack
+
+config LTT_PROBE_COMPACT
+	tristate "Linux Trace Toolkit Compact Probe"
+	depends on LTT_SERIALIZE
+	depends on LTT_HEARTBEAT_EVENT
+	depends on CRC32
+	default n
+	help
+	  Compact facility : 32 bits compact TSC and event ID. One single
+	  "compact" or "flight-compact" channel for all those events.
+
+endmenu
diff --git a/ltt/Makefile b/ltt/Makefile
new file mode 100644
index 0000000..d1e5009
--- /dev/null
+++ b/ltt/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the LTT objects.
+#
+obj-$(CONFIG_LTT)			+= ltt-core.o ltt-facilities.o \
+			 			probes/
+obj-$(CONFIG_LTT_USERSPACE_GENERIC)	+= ltt-syscall.o
+obj-$(CONFIG_LTT_HEARTBEAT)		+= ltt-heartbeat.o
+obj-$(CONFIG_LTT_TEST_TSC)		+= ltt-test-tsc.o
+obj-$(CONFIG_LTT_TRACER)		+= ltt-tracer.o
+obj-$(CONFIG_LTT_RELAY)			+= ltt-relay.o
+obj-$(CONFIG_LTT_NETLINK_CONTROL)	+= ltt-control.o
+obj-$(CONFIG_LTT_SERIALIZE)		+= ltt-serialize.o
+obj-$(CONFIG_LTT_STATEDUMP)		+= ltt-statedump.o
diff --git a/ltt/ltt-control.c b/ltt/ltt-control.c
new file mode 100644
index 0000000..26d46a1
--- /dev/null
+++ b/ltt/ltt-control.c
@@ -0,0 +1,121 @@
+/* ltt-control.c
+ *
+ * LTT control module over a netlink socket.
+ *
+ * Inspired from Relay Apps, by Tom Zanussi and iptables
+ *
+ * Copyright 2005 -
+ * 	Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ltt-tracer.h>
+#include <linux/netlink.h>
+#include <linux/inet.h>
+#include <linux/ip.h>
+#include <linux/security.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <net/sock.h>
+#include "ltt-control.h"
+
+#define LTTCTLM_BASE	0x10
+#define LTTCTLM_CONTROL	(LTTCTLM_BASE + 1)	/* LTT control message */
+
+static struct sock *socket;
+
+void ltt_control_input(struct sock *sk, int len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh = NULL;
+	u8 *payload = NULL;
+	lttctl_peer_msg_t *msg;
+	int err;
+
+	printk(KERN_DEBUG "ltt-control ltt_control_input\n");
+
+	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+
+		nlh = (struct nlmsghdr *)skb->data;
+		if (security_netlink_recv(skb, CAP_SYS_PTRACE)) {
+			netlink_ack(skb, nlh, EPERM);
+			kfree_skb(skb);
+			continue;
+		}
+		/* process netlink message pointed by skb->data */
+		err = EINVAL;
+		payload = NLMSG_DATA(nlh);
+		/* process netlink message with header pointed by 
+		 * nlh and payload pointed by payload
+		 */
+		if (nlh->nlmsg_len !=
+				sizeof(lttctl_peer_msg_t) +
+				sizeof(struct nlmsghdr)) {
+			printk(KERN_ALERT "ltt-control bad message length %d vs. %zu\n",
+				nlh->nlmsg_len, sizeof(lttctl_peer_msg_t) +
+				sizeof(struct nlmsghdr));
+			netlink_ack(skb, nlh, EINVAL);
+			kfree_skb(skb);
+			continue;
+		}
+		msg = (lttctl_peer_msg_t*)payload;
+
+		switch (msg->op) {
+			case OP_CREATE:
+				err = ltt_control(LTT_CONTROL_CREATE_TRACE,
+						msg->trace_name,
+						msg->trace_type, msg->args);
+				break;
+			case OP_DESTROY:
+				err = ltt_control(LTT_CONTROL_DESTROY_TRACE,
+						msg->trace_name,
+						msg->trace_type, msg->args);
+				break;
+			case OP_START:
+				err = ltt_control(LTT_CONTROL_START,
+						msg->trace_name,
+						msg->trace_type, msg->args);
+				break;
+			case OP_STOP:
+				err = ltt_control(LTT_CONTROL_STOP,
+						msg->trace_name,
+						msg->trace_type, msg->args);
+				break;
+			default:
+				err = EBADRQC;
+				printk(KERN_INFO 
+					"ltt-control invalid operation\n");
+		}
+		netlink_ack(skb, nlh, err);
+		kfree_skb(skb);
+	}
+}
+
+
+static int ltt_control_init(void)
+{
+	printk(KERN_INFO "ltt-control init\n");
+
+	socket = netlink_kernel_create(NETLINK_LTT, 1,
+			ltt_control_input, THIS_MODULE);
+	if (socket == NULL)
+		return -EPERM;
+	else
+		return 0;
+}
+
+static void ltt_control_exit(void)
+{
+	printk(KERN_INFO "ltt-control exit\n");
+	sock_release(socket->sk_socket);
+}
+
+
+module_init(ltt_control_init)
+module_exit(ltt_control_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Controller");
+
diff --git a/ltt/ltt-control.h b/ltt/ltt-control.h
new file mode 100644
index 0000000..15c9e16
--- /dev/null
+++ b/ltt/ltt-control.h
@@ -0,0 +1,31 @@
+/* ltt-control.h
+ *
+ * LTT control module over a netlink socket.
+ *
+ * Inspired from Relay Apps, by Tom Zanussi and iptables
+ *
+ * Copyright 2005 -
+ * 	Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ */
+
+#ifndef _LTT_CONTROL_H
+#define _LTT_CONTROL_H
+
+enum trace_op {
+	OP_CREATE,
+	OP_DESTROY,
+	OP_START,
+	OP_STOP,
+	OP_ALIGN,
+	OP_NONE
+};
+
+typedef struct lttctl_peer_msg {
+	char trace_name[NAME_MAX];
+	char trace_type[NAME_MAX];
+	enum trace_op op;
+	union ltt_control_args args;
+} lttctl_peer_msg_t;
+
+#endif //_LTT_CONTROL_H
+
diff --git a/ltt/ltt-core.c b/ltt/ltt-core.c
new file mode 100644
index 0000000..d2ade26
--- /dev/null
+++ b/ltt/ltt-core.c
@@ -0,0 +1,26 @@
+
+/*
+ * LTT core in-kernel infrastructure.
+ *
+ * Copyright 2006 - Mathieu Desnoyers mathieu.desnoyers@polymtl.ca
+ *
+ * Distributed under the GPL license
+ */
+
+#include <linux/ltt-core.h>
+#include <linux/module.h>
+
+/* Traces structures */
+struct ltt_traces ltt_traces = {
+	.head = LIST_HEAD_INIT(ltt_traces.head),
+	.num_active_traces = 0
+};
+
+EXPORT_SYMBOL(ltt_traces);
+
+volatile unsigned int ltt_nesting[NR_CPUS] = { [ 0 ... NR_CPUS-1 ] = 0 } ;
+
+EXPORT_SYMBOL(ltt_nesting);
+
+atomic_t lttng_logical_clock = ATOMIC_INIT(0);
+EXPORT_SYMBOL(lttng_logical_clock);
diff --git a/ltt/ltt-facilities.c b/ltt/ltt-facilities.c
new file mode 100644
index 0000000..1f794d4
--- /dev/null
+++ b/ltt/ltt-facilities.c
@@ -0,0 +1,344 @@
+/*
+ * ltt-facilities.c
+ *
+ * (C) Copyright	2005 -
+ *		Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Contains the kernel core code for Linux Trace Toolkit facilities.
+ *
+ * Facilities are a group of events that can be recorded by instrumentation
+ * points to a trace. We keep track of the active facilities to know which type
+ * of information can be present in a trace.
+ *
+ * We never reuse a facility id.
+ * 
+ * Author:
+ *	Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ltt-facilities.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/marker.h>
+#include <linux/ltt-tracer.h>
+
+static struct ltt_facility_info facilities[LTT_MAX_NUM_FACILITIES];
+static spinlock_t facilities_lock;
+
+int ltt_compact_facility_num_events = 0;
+EXPORT_SYMBOL_GPL(ltt_compact_facility_num_events);
+
+/* Facility registration :
+ * hash based on the checksum, except for the core facility, which is 0.
+ * This function assumes that the facility has never been registered before.
+ * User ltt_facility_verify for this. */
+int ltt_facility_register(enum ltt_facility_type type,
+		const char *name,
+		const unsigned int num_events,
+		const u32 checksum,
+		size_t int_size,
+		size_t long_size,
+		size_t pointer_size,
+		size_t size_t_size,
+		size_t alignment)
+{
+	int fac_id;
+	int chk_fac_id;
+	int found=0;
+  
+	spin_lock(&facilities_lock);
+	if (type == LTT_FACILITY_TYPE_KERNEL &&
+			strncmp(name, "core", sizeof("core")) == 0) {
+		fac_id = 0;
+	} else {
+		/* fac_id based on checksum%LTT_MAX_NUM_FACILITIES
+		 * find an empty slot */
+		chk_fac_id = fac_id = checksum % LTT_MAX_NUM_FACILITIES;
+		do {
+			if (atomic_read(&facilities[fac_id].ref) == 0) {
+				found = 1;
+				break;
+			}
+			fac_id = (fac_id+1) % LTT_MAX_NUM_FACILITIES;
+		} while (fac_id != chk_fac_id);
+
+		if (!found) {
+			fac_id = -EPERM;
+			goto unlock;
+		}
+	}
+	switch (type) {
+		case LTT_FACILITY_TYPE_USER:
+			if (strncmp(name, "user_", sizeof("user_")-1) != 0) {
+				fac_id = -EPERM;
+				goto unlock;
+			}
+			break;
+		case LTT_FACILITY_TYPE_KERNEL:
+			break;
+	}
+	strncpy(facilities[fac_id].name, name, FACNAME_LEN-1);
+	facilities[fac_id].name[FACNAME_LEN-1] = '\0';
+	facilities[fac_id].type = type;
+	facilities[fac_id].num_events = num_events;
+	facilities[fac_id].alignment = alignment;
+	facilities[fac_id].checksum = checksum;
+	facilities[fac_id].int_size = int_size;
+	facilities[fac_id].long_size = long_size;
+	facilities[fac_id].pointer_size = pointer_size;
+	facilities[fac_id].size_t_size = size_t_size;
+#ifdef CONFIG_LTT_HEARTBEAT
+	if (strcmp(name, "compact") == 0) {
+		ltt_compact_facility_num_events = facilities[fac_id].num_events;
+		ltt_init_compact_facility();
+	}
+#endif
+	if (atomic_read(&facilities[fac_id].ref) == 0) {
+		atomic_add(2, &facilities[fac_id].ref);
+		MARK(core_facility_load, "%s %4b %4b %4b %4b %4b %4b %4b",
+				facilities[fac_id].name,
+				checksum,
+				fac_id,
+				int_size,
+				long_size,
+				pointer_size,
+				size_t_size,
+				alignment);
+	} else {
+		atomic_inc(&facilities[fac_id].ref);
+	}
+unlock:
+	spin_unlock(&facilities_lock);
+	return fac_id;
+}
+
+/* Verifies if a facility is already registered. If it is,
+ * it returns the facility id. If it is not registered, it returns 0. (0 is the
+ * core facility which must never use ltt_facility_verify).
+ * If the facility is already registered, increment its refcount. */
+int ltt_facility_verify(enum ltt_facility_type type,
+		const char *name,
+		const unsigned int num_events,
+		const u32 checksum,
+		size_t int_size,
+		size_t long_size,
+		size_t pointer_size,
+		size_t size_t_size,
+		size_t alignment)
+{
+	int fac_id;
+	int chk_fac_id;
+	int found=0;
+	
+	spin_lock(&facilities_lock);
+	if (type == LTT_FACILITY_TYPE_KERNEL && 
+			strncmp(name, "core", sizeof("core")) == 0) {
+		fac_id = 0; /* Core facility */
+		goto unlock;
+	} else {
+		switch (type) {
+			case LTT_FACILITY_TYPE_USER:
+				if (strncmp(name,
+					"user_", sizeof("user_")-1) != 0) {
+					fac_id = 0;
+					goto unlock;
+				}
+				break;
+			case LTT_FACILITY_TYPE_KERNEL:
+				break;
+		}
+		/* fac_id based on checksum%LTT_MAX_NUM_FACILITIES */
+		chk_fac_id = fac_id = checksum % LTT_MAX_NUM_FACILITIES;
+		do {
+			if (facilities[fac_id].checksum == checksum) {
+				/* Possibly found : check carefully */
+				if ((atomic_read(&facilities[fac_id].ref) > 0)
+				&& strncmp(facilities[fac_id].name,
+						name, FACNAME_LEN-1) == 0 &&
+				facilities[fac_id].type == type &&
+				facilities[fac_id].num_events == num_events &&
+				facilities[fac_id].alignment == alignment &&
+				facilities[fac_id].checksum == checksum &&
+				facilities[fac_id].int_size == int_size &&
+				facilities[fac_id].long_size == long_size &&
+				facilities[fac_id].pointer_size
+					== pointer_size &&
+				facilities[fac_id].size_t_size == size_t_size) {
+					found = 1;
+					break;
+				}
+			}
+			fac_id = (fac_id+1) % LTT_MAX_NUM_FACILITIES;
+		} while (fac_id != chk_fac_id);
+		
+		if (!found) {
+			fac_id = 0;
+			goto unlock;
+		}
+		atomic_inc(&facilities[fac_id].ref);
+	}
+unlock:
+	spin_unlock(&facilities_lock);
+	return fac_id;
+}
+
+
+unsigned int ltt_facility_kernel_register(struct ltt_facility *facility)
+{
+	size_t alignment;
+#ifdef CONFIG_LTT_ALIGNMENT
+	if (facility->alignment)
+		alignment = sizeof(void*);
+	else
+		alignment = 0;
+#else
+	alignment = 0;
+#endif
+	return ltt_facility_register(LTT_FACILITY_TYPE_KERNEL,
+			facility->name, facility->num_events,
+			facility->checksum,
+			sizeof(int), sizeof(long), sizeof(void*),
+			sizeof(size_t), alignment);
+}
+
+void ltt_facility_ref(uint8_t facility_id)
+{
+	atomic_inc(&facilities[facility_id].ref);
+}
+
+int ltt_facility_unregister(uint8_t facility_id)
+{
+	int ret;
+	int freed = 0;
+
+	spin_lock(&facilities_lock);
+	if (atomic_read(&facilities[facility_id].ref) == 0) {
+		ret = -EPERM;
+		goto unlock;
+	}
+	printk(KERN_DEBUG "LTT unregister facility %hu\n", facility_id);
+	atomic_dec(&facilities[facility_id].ref);
+
+	/* Disable preemption because we read the traces list, and want it to be
+	 * RCU coherent. */
+	preempt_disable();
+	ltt_nesting[smp_processor_id()]++;
+	barrier();
+
+	/* If no more trace in the list, we can free the unused facility,
+	 * otherwise it will be freed later when the last trace is destroyed (by
+	 * ltt_facility_free_unused()). */
+	if (list_empty(&ltt_traces.head))
+		if (atomic_read(&facilities[facility_id].ref) == 1) {
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+			if (strcmp(facilities[facility_id].name,
+				"compact") == 0)
+				ltt_compact_data_shift = 0;
+#endif
+			atomic_dec(&facilities[facility_id].ref);
+			freed = 1;
+		}
+
+	barrier();
+	ltt_nesting[smp_processor_id()]--;
+	preempt_enable();
+
+	/* Ok, if we think about it, it's never going to be traced as there are
+	 * no traces in the list. In fact, we never really want to free a
+	 * facility id when there is tracing active.
+	 * FIXME : this unload could go away. */
+	if (freed)
+		MARK(core_facility_unload, "%4b", facility_id);
+	ret = 0;
+unlock:
+	spin_unlock(&facilities_lock);
+	return ret;
+}
+
+int ltt_facility_user_access_ok(uint8_t fac_id)
+{
+	if (atomic_read(&facilities[fac_id].ref) == 0)
+		return 0;
+	if (facilities[fac_id].type == LTT_FACILITY_TYPE_KERNEL)
+		return 0;
+
+	return 1;
+}
+
+/* Cleanup all the unregistered facilities. This must be done when all the
+ * traces are destroyed.
+ */
+void ltt_facility_free_unused(void)
+{
+	int fac_id;
+	
+	spin_lock(&facilities_lock);
+	for (fac_id = 0; fac_id < LTT_MAX_NUM_FACILITIES; fac_id++)
+		if (atomic_read(&facilities[fac_id].ref) == 1) {
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+			if (strcmp(facilities[fac_id].name,
+				"compact") == 0)
+				ltt_compact_data_shift = 0;
+#endif
+			atomic_dec(&facilities[fac_id].ref);
+		}
+	spin_unlock(&facilities_lock);
+}
+
+void ltt_facility_state_dump(struct ltt_trace_struct *trace)
+{
+	int fac_id;
+	struct ltt_facility_info *facility;
+	u32 int_size, long_size, pointer_size, size_t_size;
+
+	int_size = sizeof(int);
+	long_size = sizeof(long);
+	pointer_size = sizeof(void*);
+	size_t_size = sizeof(size_t);
+
+	spin_lock(&facilities_lock);
+	for (fac_id = 0; fac_id < LTT_MAX_NUM_FACILITIES; fac_id++) {
+		if (atomic_read(&facilities[fac_id].ref) > 1) {
+			facility = &facilities[fac_id];
+			printk(KERN_DEBUG "Dumping facility %s\n",
+					facility->name);
+			_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_TRACE),
+				core_state_dump_facility_load,
+				"%s %4b %4b %4b %4b %4b %4b %4b",
+				trace,
+				facility->name,
+				facility->checksum,
+				fac_id,
+				facility->int_size,
+				facility->long_size,
+				facility->pointer_size,
+				facility->size_t_size,
+				facility->alignment);
+		}
+	}
+	spin_unlock(&facilities_lock);
+}
+
+EXPORT_SYMBOL(ltt_facility_kernel_register);
+EXPORT_SYMBOL(ltt_facility_ref);
+EXPORT_SYMBOL(ltt_facility_unregister);
+EXPORT_SYMBOL(ltt_facility_free_unused);
+EXPORT_SYMBOL(ltt_facility_state_dump);
+
+static int __init ltt_facilities_init(void)
+{
+	int i;
+	printk(KERN_INFO "LTT : ltt-facilities init\n");
+
+	spin_lock_init(&facilities_lock);
+	for (i = 0; i < LTT_MAX_NUM_FACILITIES; i++) {
+		atomic_set(&facilities[i].ref, 0);
+	}
+	
+	return 0;
+}
+__initcall(ltt_facilities_init);
diff --git a/ltt/ltt-heartbeat.c b/ltt/ltt-heartbeat.c
new file mode 100644
index 0000000..ff5c346
--- /dev/null
+++ b/ltt/ltt-heartbeat.c
@@ -0,0 +1,429 @@
+/*
+ * ltt-heartbeat.c
+ *
+ * (C) Copyright	2006 -
+ * 		Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * notes : heartbeat timer cannot be used for early tracing in the boot process,
+ * as it depends on timer interrupts.
+ *
+ * The timer needs to be only on one CPU to support hotplug.
+ * We have the choice between schedule_delayed_work_on and an IPI to get each
+ * CPU to write the heartbeat. IPI have been chosen because it is considered
+ * faster than passing through the timer to get the work scheduled on all the
+ * CPUs.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/ltt-core.h>
+#include <linux/workqueue.h>
+#include <linux/cpu.h>
+#include <linux/timex.h>
+#include <linux/bitops.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+#define BITS_OF_COMPACT_DATA		11
+
+/* Expected minimum probe duration, in cycles */
+#define MIN_PROBE_DURATION		400
+/* Expected maximum interrupt latency in ms : 15ms, *2 for security */
+#define EXPECTED_INTERRUPT_LATENCY	30
+
+static struct timer_list heartbeat_timer;
+static unsigned int precalc_heartbeat_expire = 0;
+
+int ltt_compact_data_shift = 0;
+EXPORT_SYMBOL_GPL(ltt_compact_data_shift);
+
+int ltt_tsc_lsb_truncate = 0;	/* Number of LSB removed from compact tsc */
+EXPORT_SYMBOL_GPL(ltt_tsc_lsb_truncate);
+int ltt_tscbits = 0;		/* 32 - tsc_lsb_truncate - tsc_msb_cutoff */
+EXPORT_SYMBOL_GPL(ltt_tscbits);
+
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+/* For architectures with 32 bits TSC */
+static struct synthetic_tsc_struct {
+	u32 tsc[2][2];	/* a pair of 2 32 bits. [0] is the MSB, [1] is LSB */
+	unsigned int index;	/* Index of the current synth. tsc. */
+} ____cacheline_aligned synthetic_tsc[NR_CPUS];
+
+static void ltt_heartbeat_init_synthetic_cpu_tsc(int cpu)
+{
+	synthetic_tsc[cpu].tsc[0][0] = 0;	
+	synthetic_tsc[cpu].tsc[0][1] = 0;	
+	synthetic_tsc[cpu].tsc[1][0] = 0;
+	synthetic_tsc[cpu].tsc[1][1] = 0;
+	synthetic_tsc[cpu].index = 0;
+}
+
+/* Called from one CPU, before any tracing starts, to init each structure */
+static void ltt_heartbeat_init_synthetic_tsc(void)
+{
+	int cpu;
+	for_each_possible_cpu(cpu)
+		ltt_heartbeat_init_synthetic_cpu_tsc(cpu);
+	smp_wmb();
+}
+
+/* Called from heartbeat IPI : either in interrupt or process context */
+static void ltt_heartbeat_update_synthetic_tsc(void)
+{
+	struct synthetic_tsc_struct *cpu_synth;
+	u32 tsc;
+
+	preempt_disable();
+	cpu_synth = &synthetic_tsc[smp_processor_id()];
+	tsc = (u32)get_cycles();	/* We deal with a 32 LSB TSC */
+
+	if (tsc < cpu_synth->tsc[cpu_synth->index][1]) {
+		unsigned int new_index = cpu_synth->index ? 0 : 1; /* 0 <-> 1 */
+		/* Overflow */
+		/* Non atomic update of the non current synthetic TSC, followed
+		 * by an atomic index change. There is no write concurrency,
+		 * so the index read/write does not need to be atomic. */
+		cpu_synth->tsc[new_index][1] = tsc; /* LSB update */
+		cpu_synth->tsc[new_index][0] =
+			cpu_synth->tsc[cpu_synth->index][0]+1; /* MSB update */
+		cpu_synth->index = new_index;	/* atomic change of index */
+	} else {
+		/* No overflow : we can simply update the 32 LSB of the current
+		 * synthetic TSC as it's an atomic write. */
+		cpu_synth->tsc[cpu_synth->index][1] = tsc;
+	}
+	preempt_enable();
+}
+
+/* Called from buffer switch : in _any_ context (even NMI) */
+u64 ltt_heartbeat_read_synthetic_tsc(void)
+{
+	struct synthetic_tsc_struct *cpu_synth;
+	u64 ret;
+	unsigned int index;
+	u32 tsc;
+	unsigned long irqflags;
+
+	ipipe_preempt_disable(irqflags);
+	cpu_synth = &synthetic_tsc[smp_processor_id()];
+	index = cpu_synth->index; /* atomic read */
+	tsc = (u32)get_cycles();	/* We deal with a 32 LSB TSC */
+
+	if (tsc < cpu_synth->tsc[index][1]) {
+		/* Overflow */
+		ret = ((u64)(cpu_synth->tsc[index][0]+1) << 32) | ((u64)tsc);
+	} else {
+		/* no overflow */
+		ret = ((u64)cpu_synth->tsc[index][0] << 32) | ((u64)tsc);
+	}
+	ipipe_preempt_enable(irqflags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ltt_heartbeat_read_synthetic_tsc);
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+
+
+static void heartbeat_ipi(void *info)
+{
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+	ltt_heartbeat_update_synthetic_tsc();
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	/* Log a heartbeat event for each trace, each tracefile */
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL),
+		core_time_heartbeat, 
+		MARK_NOARGS,
+		GET_CHANNEL_INDEX(facilities));
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL),
+		core_time_heartbeat,
+		MARK_NOARGS,
+		GET_CHANNEL_INDEX(interrupts));
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL),
+		core_time_heartbeat,
+		MARK_NOARGS,
+		GET_CHANNEL_INDEX(processes));
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL),
+		core_time_heartbeat,
+		MARK_NOARGS,
+		GET_CHANNEL_INDEX(modules));
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL),
+		core_time_heartbeat,
+		MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu));
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL),
+		core_time_heartbeat,
+		MARK_NOARGS,
+		GET_CHANNEL_INDEX(network));
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT),
+		compact_time_heartbeat,
+		MARK_NOARGS);
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+}
+
+static void heartbeat_ipi_full(void *info)
+{
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+	ltt_heartbeat_update_synthetic_tsc();
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	/* Log a heartbeat event for each trace, each tracefile */
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		core_time_heartbeat_full,
+		"%8b",
+		GET_CHANNEL_INDEX(facilities),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		core_time_heartbeat_full,
+		"%8b",
+		GET_CHANNEL_INDEX(interrupts),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		core_time_heartbeat_full,
+		"%8b",
+		GET_CHANNEL_INDEX(processes),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		core_time_heartbeat_full,
+		"%8b",
+		GET_CHANNEL_INDEX(modules),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		core_time_heartbeat_full,
+		"%8b",
+		GET_CHANNEL_INDEX(cpu),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_CHANNEL)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		core_time_heartbeat_full,
+		"%8b",
+		GET_CHANNEL_INDEX(network),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_COMPACT)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		compact_time_heartbeat_full,
+		"%8b",
+		ltt_get_timestamp64());
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+}
+
+/* Write the full TSC in the traces. To be called when we cannot assume that the heartbeat events
+ * will keep a trace buffer synchronized. (missing timer events, tracing starts, tracing restarts)
+ */
+void ltt_write_full_tsc(void)
+{
+	on_each_cpu(heartbeat_ipi_full, NULL, 1, 0);
+}
+EXPORT_SYMBOL_GPL(ltt_write_full_tsc);
+
+/* We need to be in process context to do an IPI */
+static void heartbeat_work(struct work_struct *work)
+{
+	on_each_cpu(heartbeat_ipi, NULL, 1, 0);
+}
+static DECLARE_WORK(hb_work, heartbeat_work);
+
+/**
+ * heartbeat_timer : - Timer function generating hearbeat.
+ * @data: unused
+ *
+ * Guarantees at least 1 execution of heartbeat before low word of TSC wraps.
+ */
+static void heartbeat_timer_fct(unsigned long data)
+{
+	PREPARE_WORK(&hb_work, heartbeat_work);
+	schedule_work(&hb_work);
+	
+	mod_timer(&heartbeat_timer, jiffies + precalc_heartbeat_expire);
+}
+
+
+/**
+ * init_heartbeat_timer: - Start timer generating hearbeat events.
+ */
+static void init_heartbeat_timer(void)
+{
+	int tsc_msb_cutoff;
+	int data_bits = BITS_OF_COMPACT_DATA;
+	int max_tsc_msb_cutoff;
+	unsigned long mask;
+
+	if (loops_per_jiffy > 0) {
+		printk(KERN_DEBUG "LTT : ltt-heartbeat init\n");
+		printk("Requested number of bits %d\n", data_bits);
+
+		ltt_tsc_lsb_truncate = max(0,
+			(int)get_count_order(MIN_PROBE_DURATION)-1);
+		max_tsc_msb_cutoff =
+			32 - 1 - get_count_order(((1UL << 1)
+			+ (EXPECTED_INTERRUPT_LATENCY*HZ/1000)
+			+ LTT_PERCPU_TIMER_INTERVAL + 1)
+			* (loops_per_jiffy << 1));
+		printk("Available number of bits %d\n",
+			ltt_tsc_lsb_truncate + max_tsc_msb_cutoff);
+		if (ltt_tsc_lsb_truncate + max_tsc_msb_cutoff < 
+			data_bits) {
+			printk("Number of bits truncated to %d\n",
+				ltt_tsc_lsb_truncate + max_tsc_msb_cutoff);
+			data_bits = ltt_tsc_lsb_truncate + max_tsc_msb_cutoff;
+		}
+			
+		tsc_msb_cutoff = data_bits - ltt_tsc_lsb_truncate;
+
+		if (tsc_msb_cutoff > 0)
+			mask = (1UL<<(32-tsc_msb_cutoff))-1;
+		else
+			mask = 0xFFFFFFFFUL;
+		precalc_heartbeat_expire =
+			(mask/(loops_per_jiffy << 1)
+				- 1 - LTT_PERCPU_TIMER_INTERVAL
+				- (EXPECTED_INTERRUPT_LATENCY*HZ/1000)) >> 1;
+		WARN_ON(precalc_heartbeat_expire == 0);
+		printk("Heartbeat timer will fire each %u jiffies.\n",
+			precalc_heartbeat_expire);
+
+		//precalc_heartbeat_expire = ( 0xFFFFFFFFUL/(loops_per_jiffy << 1)
+		//	- 1 - LTT_PERCPU_TIMER_INTERVAL) >> 1;
+
+		//tsc_msb_cutoff = 32 - 1 -
+		//	get_count_order(( (EXPECTED_INTERRUPT_LATENCY
+		//		+ (precalc_heartbeat_expire * 1000 / HZ))
+		//		* cpu_khz ));
+		ltt_tscbits = 32 - ltt_tsc_lsb_truncate - tsc_msb_cutoff;
+		printk("Compact TSC init : truncate %d lsb, cutoff %d msb.\n",
+			ltt_tsc_lsb_truncate, tsc_msb_cutoff);
+	} else
+		printk(KERN_WARNING
+			"LTT: no tsc for heartbeat timer "
+			"- continuing without one \n");
+}
+
+/* ltt_init_compact_facility reserves the number of bits to identify the event
+ * numbers in the compact headers. It must be called every time the compact
+ * facility is changed. */
+void ltt_init_compact_facility(void)
+{
+	if (loops_per_jiffy > 0) {
+		ltt_compact_data_shift =
+			get_count_order(ltt_compact_facility_num_events)
+						+ ltt_tscbits;
+		printk("Data shifted from %d bits\n", ltt_compact_data_shift);
+
+		printk("%d bits used for event IDs, %d available for data.\n",
+			get_count_order(ltt_compact_facility_num_events),
+			32 - ltt_compact_data_shift);
+	} else
+		printk(KERN_WARNING
+			"LTT: no tsc for heartbeat timer "
+			"- continuing without one \n");
+}
+EXPORT_SYMBOL_GPL(ltt_init_compact_facility);
+
+
+static void start_heartbeat_timer(void)
+{
+	if (precalc_heartbeat_expire > 0) {
+		printk(KERN_DEBUG "LTT : ltt-heartbeat start\n");
+
+		init_timer(&heartbeat_timer);
+		heartbeat_timer.function = heartbeat_timer_fct;
+		heartbeat_timer.expires = jiffies + precalc_heartbeat_expire;
+		add_timer(&heartbeat_timer);
+	} else
+		printk(KERN_WARNING
+			"LTT: no tsc for heartbeat timer "
+			"- continuing without one \n");
+}
+
+/**
+ * stop_heartbeat_timer: - Stop timer generating hearbeat events.
+ */
+static void stop_heartbeat_timer(void)
+{
+ 	if (loops_per_jiffy > 0) {
+		printk(KERN_DEBUG "LTT : ltt-heartbeat stop\n");
+		del_timer(&heartbeat_timer);
+	}
+}
+
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+/**
+ * 	heartbeat_hotcpu_callback - CPU hotplug callback
+ * 	@nb: notifier block
+ * 	@action: hotplug action to take
+ * 	@hcpu: CPU number
+ *	
+ *	Sets the new CPU's current synthetic TSC to the same value as the
+ *	currently running CPU.
+ *
+ * 	Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD)
+ */
+static int __cpuinit heartbeat_hotcpu_callback(struct notifier_block *nb,
+				unsigned long action,
+				void *hcpu)
+{
+	unsigned int hotcpu = (unsigned long)hcpu;
+	struct synthetic_tsc_struct *cpu_synth;
+	u64 local_count;
+
+	switch(action) {
+	case CPU_UP_PREPARE:
+		ltt_heartbeat_init_synthetic_cpu_tsc(hotcpu);
+		cpu_synth = &synthetic_tsc[hotcpu];
+		local_count = ltt_heartbeat_read_synthetic_tsc();
+		cpu_synth->tsc[0][1] = (u32)local_count; /* LSB */
+		cpu_synth->tsc[0][0] = (u32)(local_count >> 32); /* MSB */
+		smp_wmb();
+		break;
+	case CPU_ONLINE:
+		/* FIXME : heartbeat events are currently broken with CPU
+		 * hotplug : events can be recorded before heartbeat, heartbeat
+		 * too far from trace start and are broken with trace
+		 * stop/start as well.
+		 */
+		/* As we are preemptible, make sure it runs on the right cpu */
+		smp_call_function_single(hotcpu, heartbeat_ipi, NULL, 1, 0);
+		break;
+	}
+	return NOTIFY_OK;
+}
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+
+int ltt_heartbeat_trigger(enum ltt_heartbeat_functor_msg msg)
+{
+	printk(KERN_DEBUG "LTT : ltt-heartbeat trigger\n");
+	switch (msg) {
+		case LTT_HEARTBEAT_START:
+			start_heartbeat_timer();
+			break;
+		case LTT_HEARTBEAT_STOP:
+			stop_heartbeat_timer();
+			break;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ltt_heartbeat_trigger);
+
+static int __init ltt_heartbeat_init(void)
+{
+	printk(KERN_INFO "LTT : ltt-heartbeat init\n");
+#ifdef CONFIG_LTT_SYNTHETIC_TSC
+	/* higher priority than relay */
+	hotcpu_notifier(heartbeat_hotcpu_callback, 1);
+	ltt_heartbeat_init_synthetic_tsc();
+#endif //CONFIG_LTT_SYNTHETIC_TSC
+	init_heartbeat_timer();
+	return 0;
+}
+
+__initcall(ltt_heartbeat_init);
diff --git a/ltt/ltt-relay.c b/ltt/ltt-relay.c
new file mode 100644
index 0000000..5fe0beb
--- /dev/null
+++ b/ltt/ltt-relay.c
@@ -0,0 +1,1282 @@
+/*
+ * ltt-relay.c
+ *
+ * (C) Copyright 2005-2006 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Contains the kernel code for the Linux Trace Toolkit.
+ *
+ * Author:
+ *	Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Inspired from LTT :
+ *	Karim Yaghmour (karim@opersys.com)
+ *	Tom Zanussi (zanussi@us.ibm.com)
+ *	Bob Wisniewski (bob@watson.ibm.com)
+ * And from K42 :
+ *  Bob Wisniewski (bob@watson.ibm.com)
+ *
+ * Changelog:
+ *  19/10/05, Complete lockless mechanism. (Mathieu Desnoyers)
+ *	27/05/05, Modular redesign and rewrite. (Mathieu Desnoyers)
+
+ * Comments :
+ * num_active_traces protects the functors. Changing the pointer is an atomic
+ * operation, but the functions can only be called when in tracing. It is then
+ * safe to unload a module in which sits a functor when no tracing is active.
+ *
+ * filter_control functor is protected by incrementing its module refcount.
+ *
+ */
+
+#include <linux/time.h>
+#include <linux/ltt-tracer.h>
+#include <linux/relay.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/ltt-facilities.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/debugfs.h>
+#include <linux/stat.h>
+#include <linux/cpu.h>
+#include <asm/atomic.h>
+#include <asm/local.h>
+
+static struct dentry *ltt_root_dentry;
+static struct file_operations ltt_file_operations;
+
+/* How a force_switch must be done ?
+ *
+ * Is it done during tracing or as a final flush after tracing
+ * (so it won't write in the new sub-buffer).
+ */
+enum force_switch_mode { FORCE_ACTIVE, FORCE_FLUSH };
+
+static int ltt_relay_create_buffer(struct ltt_trace_struct *trace,
+	struct ltt_channel_struct *ltt_chan,
+	struct rchan_buf *buf,
+	unsigned int cpu,
+	unsigned n_subbufs);
+
+static void ltt_relay_destroy_buffer(struct ltt_channel_struct *ltt_chan,
+		unsigned int cpu);
+
+/* Trace callbacks */
+
+static void ltt_buffer_begin_callback(struct rchan_buf *buf,
+			u64 tsc, unsigned int subbuf_idx)
+{
+	struct ltt_channel_struct *channel =
+		(struct ltt_channel_struct*)buf->chan->private_data;
+	struct ltt_block_start_header *header =
+		(struct ltt_block_start_header*)
+			(buf->start + (subbuf_idx*buf->chan->subbuf_size));
+
+	header->begin.cycle_count = tsc;
+	header->begin.freq = ltt_frequency();
+	header->lost_size = 0xFFFFFFFF; // for debugging...
+	header->buf_size = buf->chan->subbuf_size;
+	ltt_write_trace_header(channel->trace, &header->trace);
+}
+
+static void ltt_buffer_end_callback(struct rchan_buf *buf,
+			u64 tsc, unsigned int offset, unsigned int subbuf_idx)
+{
+	struct ltt_block_start_header *header =
+		(struct ltt_block_start_header*)
+			(buf->start + (subbuf_idx*buf->chan->subbuf_size));
+
+	/* offset is assumed to never be 0 here : never deliver a completely
+	 * empty subbuffer.
+	 * The lost size is between 0 and subbuf_size-1 */
+	header->lost_size = SUBBUF_OFFSET((buf->chan->subbuf_size - offset),
+				buf->chan);
+	header->end.cycle_count = tsc;
+	header->end.freq = ltt_frequency();
+}
+
+static int ltt_subbuf_start_callback(struct rchan_buf *buf,
+				void *subbuf,
+				void *prev_subbuf,
+				size_t prev_padding)
+{
+	return 0;
+}
+
+
+
+static void ltt_deliver(struct rchan_buf *buf,
+		unsigned subbuf_idx,
+		void *subbuf)
+{
+	struct ltt_channel_struct *channel =
+		(struct ltt_channel_struct*)buf->chan->private_data;
+	struct ltt_channel_buf_struct *ltt_buf = &channel->buf[buf->cpu];
+
+	atomic_set(&ltt_buf->wakeup_readers, 1);
+}
+
+static void ltt_buf_mapped_callback(struct rchan_buf *buf,
+		struct file *filp)
+{
+}
+
+static void ltt_buf_unmapped_callback(struct rchan_buf *buf,
+		struct file *filp)
+{
+}
+
+static struct dentry *ltt_create_buf_file_callback(const char *filename,
+				  struct dentry *parent,
+				  int mode,
+				  struct rchan_buf *buf,
+				  int *is_global)
+{
+	struct ltt_channel_struct *ltt_chan;
+	int err;
+	struct dentry *dentry;
+
+	ltt_chan = buf->chan->private_data;
+	err = ltt_relay_create_buffer(ltt_chan->trace, ltt_chan,
+					buf, buf->cpu,
+					buf->chan->n_subbufs);
+	if(err)
+		return ERR_PTR(err);
+
+	dentry = debugfs_create_file(filename, mode, parent, buf,
+			&ltt_file_operations);
+	if(!dentry)
+		goto error;
+	return dentry;
+error:
+	ltt_relay_destroy_buffer(ltt_chan, buf->cpu);
+	return NULL;
+}
+
+static int ltt_remove_buf_file_callback(struct dentry *dentry)
+{
+	struct rchan_buf *buf = dentry->d_inode->i_private;
+	struct ltt_channel_struct *ltt_chan = buf->chan->private_data;
+
+	debugfs_remove(dentry);
+	ltt_relay_destroy_buffer(ltt_chan, buf->cpu);
+
+	return 0;
+}
+
+/* This function should not be called from NMI interrupt context */
+static void ltt_buf_unfull(struct rchan_buf *buf,
+		unsigned subbuf_idx,
+		void *subbuf)
+{
+	struct ltt_channel_struct *ltt_channel =
+		(struct ltt_channel_struct*)buf->chan->private_data;
+	struct ltt_channel_buf_struct *ltt_buf = &ltt_channel->buf[buf->cpu];
+	if (waitqueue_active(&ltt_buf->write_wait))
+		schedule_work(&ltt_buf->wake_writers);
+}
+
+
+/**
+ *	ltt_poll - poll file op for ltt files
+ *	@filp: the file
+ *	@wait: poll table
+ *
+ *	Poll implemention.
+ */
+static unsigned int ltt_poll(struct file *filp, poll_table *wait)
+{
+	unsigned int mask = 0;
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct rchan_buf *buf = inode->i_private;
+	struct ltt_channel_struct *ltt_channel =
+		(struct ltt_channel_struct*)buf->chan->private_data;
+	struct ltt_channel_buf_struct *ltt_buf = &ltt_channel->buf[buf->cpu];
+
+	//printk(KERN_DEBUG "DEBUG : in LTT poll %p\n", filp);
+	if (filp->f_mode & FMODE_READ) {
+		poll_wait(filp, &buf->read_wait, wait);
+
+		if (atomic_long_read(&ltt_buf->active_readers) != 0) {
+			return 0;
+		} else {
+			if (SUBBUF_TRUNC(
+				local_read(&ltt_buf->offset), buf->chan)
+			- SUBBUF_TRUNC(
+				atomic_long_read(&ltt_buf->consumed), buf->chan)
+			== 0) {
+				if (buf->finalized) return POLLHUP;
+				else return 0;
+			} else {
+				struct rchan *rchan =
+					ltt_channel->trans_channel_data;
+				if (SUBBUF_TRUNC(local_read(&ltt_buf->offset),
+						buf->chan)
+			- SUBBUF_TRUNC(atomic_long_read(&ltt_buf->consumed),
+							buf->chan)
+				>= rchan->alloc_size)
+					return POLLPRI | POLLRDBAND;
+				else
+					return POLLIN | POLLRDNORM;
+			}
+		}
+	}
+	return mask;
+}
+
+
+/**
+ *	ltt_ioctl - ioctl control on the debugfs file
+ *
+ *	@inode: the inode
+ *	@filp: the file
+ *	@cmd: the command
+ *	@arg: command arg
+ *
+ *	This ioctl implements three commands necessary for a minimal
+ *	producer/consumer implementation :
+ *	RELAY_GET_SUBBUF
+ *		Get the next sub buffer that can be read. It never blocks.
+ *	RELAY_PUT_SUBBUF
+ *		Release the currently read sub-buffer. Parameter is the last
+ *		put subbuffer (returned by GET_SUBBUF).
+ *	RELAY_GET_N_BUBBUFS
+ *		returns the number of sub buffers in the per cpu channel.
+ *	RELAY_GET_SUBBUF_SIZE
+ *		returns the size of the sub buffers.
+ *
+ */
+static int ltt_ioctl(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	struct rchan_buf *buf = inode->i_private;
+	struct ltt_channel_struct *ltt_channel =
+		(struct ltt_channel_struct*)buf->chan->private_data;
+	struct ltt_channel_buf_struct *ltt_buf = &ltt_channel->buf[buf->cpu];
+	u32 __user *argp = (u32 __user *)arg;
+
+	switch (cmd) {
+		case RELAY_GET_SUBBUF:
+		{
+			long consumed_old, consumed_idx;
+			atomic_long_inc(&ltt_buf->active_readers);
+			consumed_old = atomic_long_read(&ltt_buf->consumed);
+			consumed_idx = SUBBUF_INDEX(consumed_old, buf->chan);
+			if (SUBBUF_OFFSET(
+				local_read(
+					&ltt_buf->commit_count[consumed_idx]),
+				buf->chan) != 0) {
+				atomic_long_dec(&ltt_buf->active_readers);
+				return -EAGAIN;
+			}
+			if ((SUBBUF_TRUNC(
+				local_read(&ltt_buf->offset), buf->chan)
+			- SUBBUF_TRUNC(consumed_old, buf->chan))
+			== 0) {
+				atomic_long_dec(&ltt_buf->active_readers);
+				return -EAGAIN;
+			}
+			smp_rmb();
+			//printk(KERN_DEBUG "LTT ioctl get subbuf %d\n",
+			//		consumed_old);
+			return put_user((u32)consumed_old, argp);
+			break;
+		}
+		case RELAY_PUT_SUBBUF:
+		{
+			u32 uconsumed_old;
+			int ret;
+			long consumed_new, consumed_old;
+
+			ret = get_user(uconsumed_old, argp);
+			if (ret)
+				return ret; /* will return -EFAULT */
+
+			//printk(KERN_DEBUG "LTT ioctl put subbuf %d\n",
+			//		consumed_old);
+			consumed_old = atomic_long_read(&ltt_buf->consumed);
+			consumed_old = consumed_old & (~0xFFFFFFFFL);
+			consumed_old = consumed_old | uconsumed_old;
+			consumed_new = SUBBUF_ALIGN(consumed_old, buf->chan);
+
+			spin_lock(&ltt_buf->full_lock);
+			if (atomic_long_cmpxchg(
+				&ltt_buf->consumed, consumed_old, consumed_new)
+					!= consumed_old) {
+				/* We have been pushed by the writer : the last
+				 * buffer read _is_ corrupted! It can also
+				 * happen if this is a buffer we never got. */
+				atomic_long_dec(&ltt_buf->active_readers);
+				spin_unlock(&ltt_buf->full_lock);
+				return -EIO;
+			} else {
+				/* tell the client that buffer is now unfull */
+				int index;
+				void *data;
+				index = SUBBUF_INDEX(consumed_old, buf->chan);
+				data = buf->start +
+					BUFFER_OFFSET(consumed_old, buf->chan);
+				ltt_buf_unfull(buf, index, data);
+				atomic_long_dec(&ltt_buf->active_readers);
+				spin_unlock(&ltt_buf->full_lock);
+			}
+			break;
+		}
+		case RELAY_GET_N_SUBBUFS:
+			//printk(KERN_DEBUG "LTT ioctl get n subbufs\n");
+			return put_user((u32)buf->chan->n_subbufs, argp);
+			break;
+		case RELAY_GET_SUBBUF_SIZE:
+			//printk(KERN_DEBUG "LTT ioctl get subbuf size\n");
+			return put_user((u32)buf->chan->subbuf_size, argp);
+			break;
+		default:
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+
+static long ltt_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	long ret = -ENOIOCTLCMD;
+
+	lock_kernel();
+	ret = ltt_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+	unlock_kernel();
+
+	return ret;
+}
+
+#endif //CONFIG_COMPAT
+
+static void ltt_relay_print_subbuffer_errors(
+	struct ltt_channel_struct *ltt_chan,
+	long cons_off, unsigned int i)
+{
+	struct rchan *rchan = ltt_chan->trans_channel_data;
+	long cons_idx;
+
+	printk(KERN_WARNING
+		"LTT : unread channel %s offset is %ld "
+		"and cons_off : %ld (cpu %u)\n",
+		ltt_chan->channel_name,
+		local_read(&ltt_chan->buf[i].offset), cons_off, i);
+	/* Check each sub-buffer for non zero commit count */
+	cons_idx = SUBBUF_INDEX(cons_off, rchan);
+	if (SUBBUF_OFFSET(local_read(&ltt_chan->buf[i].commit_count[cons_idx]),
+				rchan))
+		printk(KERN_ALERT
+			"LTT : %s : subbuffer %lu has non zero "
+			"commit count.\n",
+			ltt_chan->channel_name, cons_idx);
+	printk(KERN_ALERT "LTT : %s : commit count : %lu, subbuf size %zd\n",
+			ltt_chan->channel_name,
+			local_read(&ltt_chan->buf[i].commit_count[cons_idx]),
+			rchan->subbuf_size);
+}
+
+static void ltt_relay_print_errors(struct ltt_trace_struct *trace,
+		struct ltt_channel_struct *ltt_chan, int cpu)
+{
+	struct rchan *rchan = ltt_chan->trans_channel_data;
+	long cons_off;
+
+	for (cons_off = atomic_long_read(&ltt_chan->buf[cpu].consumed);
+		(SUBBUF_TRUNC(local_read(&ltt_chan->buf[cpu].offset),
+				rchan)
+			- cons_off) > 0;
+		cons_off = SUBBUF_ALIGN(cons_off, rchan)) {
+		ltt_relay_print_subbuffer_errors(ltt_chan, cons_off, cpu);
+	}
+}
+
+static void ltt_relay_print_buffer_errors(struct ltt_channel_struct *ltt_chan,
+			unsigned int cpu)
+{
+	struct ltt_trace_struct *trace = ltt_chan->trace;
+	
+	if (local_read(&ltt_chan->buf[cpu].events_lost))
+		printk(KERN_ALERT 
+			"LTT : %s : %ld events lost "
+			"in %s channel (cpu %u).\n",
+			ltt_chan->channel_name,
+			local_read(&ltt_chan->buf[cpu].events_lost),
+			ltt_chan->channel_name, cpu);
+	if (local_read(&ltt_chan->buf[cpu].corrupted_subbuffers))
+		printk(KERN_ALERT 
+			"LTT : %s : %ld corrupted subbuffers "
+			"in %s channel (cpu %u).\n",
+			ltt_chan->channel_name,
+			local_read(
+				&ltt_chan->buf[cpu].corrupted_subbuffers),
+			ltt_chan->channel_name, cpu);
+
+	ltt_relay_print_errors(trace, ltt_chan, cpu);
+}
+
+static void ltt_relay_remove_dirs(struct ltt_trace_struct *trace)
+{
+	debugfs_remove(trace->dentry.control_root);
+	debugfs_remove(trace->dentry.trace_root);
+}
+
+static void ltt_relay_release_channel(struct kref *kref)
+{
+	struct ltt_channel_struct *ltt_chan = container_of(kref,
+			struct ltt_channel_struct, kref);
+	kfree(ltt_chan);
+}
+
+/* Create ltt buffer.
+ */
+static int ltt_relay_create_buffer(struct ltt_trace_struct *trace,
+	struct ltt_channel_struct *ltt_chan,
+	struct rchan_buf *buf,
+	unsigned int cpu,
+	unsigned n_subbufs)
+{
+	unsigned int j;
+
+	ltt_chan->buf[cpu].commit_count =
+		kmalloc(sizeof(local_t) * n_subbufs, GFP_KERNEL);
+	if (!ltt_chan->buf[cpu].commit_count)
+		return -ENOMEM;
+	kref_get(&trace->kref);
+	kref_get(&trace->ltt_transport_kref);
+	kref_get(&ltt_chan->kref);
+	local_set(&ltt_chan->buf[cpu].offset,
+		ltt_subbuf_header_len());
+	atomic_long_set(&ltt_chan->buf[cpu].consumed, 0);
+	atomic_long_set(&ltt_chan->buf[cpu].active_readers, 0);
+	for (j = 0; j < n_subbufs; j++)
+		local_set(&ltt_chan->buf[cpu].commit_count[j], 0);
+	init_waitqueue_head(&ltt_chan->buf[cpu].write_wait);
+	atomic_set(&ltt_chan->buf[cpu].wakeup_readers, 0);
+	INIT_WORK(&ltt_chan->buf[cpu].wake_writers, ltt_wakeup_writers);
+	spin_lock_init(&ltt_chan->buf[cpu].full_lock);
+	
+	ltt_buffer_begin_callback(buf, trace->start_tsc, 0);
+	/* atomic_add made on local variable on data that belongs to
+	 * various CPUs : ok because tracing not started (for this cpu). */
+	local_add(ltt_subbuf_header_len(),
+		&ltt_chan->buf[cpu].commit_count[0]);
+
+	local_set(&ltt_chan->buf[cpu].events_lost, 0);
+	local_set(&ltt_chan->buf[cpu].corrupted_subbuffers, 0);
+
+	return 0;
+}
+
+static void ltt_relay_destroy_buffer(struct ltt_channel_struct *ltt_chan,
+					unsigned int cpu)
+{
+	struct ltt_trace_struct *trace = ltt_chan->trace;
+
+	kref_put(&ltt_chan->trace->ltt_transport_kref,
+		ltt_release_transport);
+	ltt_relay_print_buffer_errors(ltt_chan, cpu);
+	kfree(ltt_chan->buf[cpu].commit_count);
+	ltt_chan->buf[cpu].commit_count = NULL;
+	kref_put(&ltt_chan->kref, ltt_relay_release_channel);
+	kref_put(&trace->kref, ltt_release_trace);
+}
+
+/* Create channel.
+ */
+static int ltt_relay_create_channel(char *trace_name,
+		struct ltt_trace_struct *trace,
+		struct dentry *dir,
+		char *channel_name,
+		struct ltt_channel_struct **ltt_chan,
+		unsigned int subbuf_size, unsigned int n_subbufs,
+		int overwrite)
+{
+	char *tmpname;
+	unsigned int tmpname_len;
+	int err = 0;
+
+	tmpname = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!tmpname)
+		return EPERM;
+	if (overwrite) {
+		strncpy(tmpname, LTT_FLIGHT_PREFIX, PATH_MAX-1);
+		strncat(tmpname, channel_name,
+			PATH_MAX-1-sizeof(LTT_FLIGHT_PREFIX));
+	} else {
+		strncpy(tmpname, channel_name, PATH_MAX-1);
+	}
+	strncat(tmpname, "_", PATH_MAX-1-strlen(tmpname));
+
+	*ltt_chan = kzalloc(sizeof(struct ltt_channel_struct), GFP_KERNEL);
+	if (!(*ltt_chan))
+		goto ltt_chan_alloc_error;
+	kref_init(&(*ltt_chan)->kref);
+
+	(*ltt_chan)->trace = trace;
+	(*ltt_chan)->buffer_begin = ltt_buffer_begin_callback;
+	(*ltt_chan)->buffer_end = ltt_buffer_end_callback;
+	(*ltt_chan)->overwrite = overwrite;
+	if (strcmp(channel_name, LTT_COMPACT_CHANNEL) == 0)
+		(*ltt_chan)->compact = 1;
+	else
+		(*ltt_chan)->compact = 0;
+	(*ltt_chan)->trans_channel_data = relay_open(tmpname,
+			dir,
+			subbuf_size,
+			n_subbufs,
+			&trace->callbacks,
+			*ltt_chan);
+	tmpname_len = strlen(tmpname);
+	if (tmpname_len > 0) {
+		/* Remove final _ for pretty printing */
+		tmpname[tmpname_len-1] = '\0';
+	}
+	if ((*ltt_chan)->trans_channel_data == NULL) {
+		printk(KERN_ERR "LTT : Can't open %s channel for trace %s\n",
+				tmpname, trace_name);
+		goto relay_open_error;
+	}
+
+	strncpy((*ltt_chan)->channel_name, tmpname, PATH_MAX-1);
+
+	err = 0;
+	goto end;
+
+relay_open_error:
+	kfree(*ltt_chan);
+	*ltt_chan = NULL;
+ltt_chan_alloc_error:
+	err = EPERM;
+end:
+	kfree(tmpname);
+	return err;
+}
+
+static int ltt_relay_create_dirs(struct ltt_trace_struct *new_trace)
+{
+	new_trace->dentry.trace_root = debugfs_create_dir(new_trace->trace_name,
+			ltt_root_dentry);
+	if (new_trace->dentry.trace_root == NULL) {
+		printk(KERN_ERR "LTT : Trace directory name %s already taken\n",
+				new_trace->trace_name);
+		return EEXIST;
+	}
+
+	new_trace->dentry.control_root = debugfs_create_dir(LTT_CONTROL_ROOT,
+			new_trace->dentry.trace_root);
+	if (new_trace->dentry.control_root == NULL) {
+		printk(KERN_ERR "LTT : Trace control subdirectory name "\
+				"%s/%s already taken\n",
+				new_trace->trace_name, LTT_CONTROL_ROOT);
+		debugfs_remove(new_trace->dentry.trace_root);
+		return EEXIST;
+	}
+
+	new_trace->callbacks.subbuf_start = ltt_subbuf_start_callback;
+	new_trace->callbacks.buf_mapped = ltt_buf_mapped_callback;
+	new_trace->callbacks.buf_unmapped = ltt_buf_unmapped_callback;
+	new_trace->callbacks.create_buf_file = ltt_create_buf_file_callback;
+	new_trace->callbacks.remove_buf_file = ltt_remove_buf_file_callback;
+
+	return 0;
+}
+
+/* Force a sub-buffer switch for a per-cpu buffer. This operation is
+ * completely reentrant : can be called while tracing is active with
+ * absolutely no lock held.
+ *
+ * Note, however, that as an local_cmpxchg is used for some atomic
+ * operations, this function must be called from the CPU which owns the buffer
+ * for a ACTIVE flush.
+ */
+static void ltt_force_switch(struct rchan_buf *buf, enum force_switch_mode mode)
+{
+	struct ltt_channel_struct *ltt_channel =
+			(struct ltt_channel_struct*)buf->chan->private_data;
+	struct ltt_channel_buf_struct *ltt_buf = &ltt_channel->buf[buf->cpu];
+	struct rchan *rchan = ltt_channel->trans_channel_data;
+
+	u64 tsc;
+	long offset_begin, offset_end, offset_old;
+	long reserve_commit_diff;
+	long consumed_old, consumed_new;
+	long commit_count;
+	long end_switch_old;
+
+	do {
+		offset_old = local_read(&ltt_buf->offset);
+		offset_begin = offset_old;
+		end_switch_old = 0;
+
+		if (SUBBUF_OFFSET(offset_begin, buf->chan) != 0) {
+			offset_begin = SUBBUF_ALIGN(offset_begin, buf->chan);
+			end_switch_old = 1;
+		} else {
+			/* we do not have to switch : buffer is empty */
+			return;
+		}
+		if (mode == FORCE_ACTIVE)
+			offset_begin += ltt_subbuf_header_len();
+		/* Always begin_switch in FORCE_ACTIVE mode */
+		/* Test new buffer integrity */
+		reserve_commit_diff = SUBBUF_OFFSET(
+			buf->chan->subbuf_size
+			- local_read(
+			&ltt_buf->commit_count[SUBBUF_INDEX(offset_begin,
+						buf->chan)]), buf->chan);
+		if (reserve_commit_diff == 0) {
+			/* Next buffer not corrupted. */
+			if (mode == FORCE_ACTIVE && !ltt_channel->overwrite &&
+			(offset_begin - atomic_long_read(&ltt_buf->consumed))
+				>= rchan->alloc_size) {
+	  			/* We do not overwrite non consumed buffers
+				 * and we are full :
+				 * ignore switch while tracing is active. */
+				return;
+			}
+		} else {
+			/* Next subbuffer corrupted. Force pushing reader even
+			 * in normal mode */
+		}
+		offset_end = offset_begin;
+
+		tsc = ltt_get_timestamp64();
+		if (tsc == 0) {
+			/* Error in getting the timestamp : should not happen :
+			 * it would mean we are called from an NMI during a
+			 * write seqlock on xtime. */
+			return;
+		}
+	} while (local_cmpxchg(&ltt_buf->offset, offset_old, offset_end)
+							!= offset_old);
+
+	if (mode == FORCE_ACTIVE) {
+		/* Push the reader if necessary */
+		do {
+			consumed_old = atomic_long_read(&ltt_buf->consumed);
+			/* If buffer is in overwrite mode, push the reader
+			 * consumed count if the write position has reached it
+			 * and we are not at the first iteration (don't push
+			 * the reader farther than the writer). This operation
+			 * can be done concurrently by many writers in the same
+			 * buffer, the writer being at the fartest write
+			 * position sub-buffer index in the buffer being the
+			 * one which will win this loop.
+			 * If the buffer is not in overwrite mode, pushing the
+			 * reader only happen if a sub-buffer is corrupted */
+			if ((SUBBUF_TRUNC(offset_end-1, buf->chan)
+					- SUBBUF_TRUNC(consumed_old,
+						buf->chan))
+					>= rchan->alloc_size)
+				consumed_new =
+					SUBBUF_ALIGN(consumed_old, buf->chan);
+			else {
+				consumed_new = consumed_old;
+				break;
+			}
+		} while (atomic_long_cmpxchg(&ltt_buf->consumed, consumed_old,
+					consumed_new) != consumed_old);
+
+		if (consumed_old != consumed_new) {
+			/* Reader pushed : we are the winner of the push, we
+			 * can therefore reequilibrate reserve and commit.
+			 * Atomic increment of the commit count permits other
+			 * writers to play around with this variable before us.
+			 * We keep track of corrupted_subbuffers even in
+			 * overwrite mode :
+			 * we never want to write over a non completely
+			 * committed sub-buffer : possible causes : the buffer
+			 * size is too low compared to the unordered data input,
+			 * or there is a writer who died between the reserve
+			 * and the commit. */
+			if (reserve_commit_diff) {
+				/* We have to alter the sub-buffer commit
+				 * count : a sub-buffer is corrupted */
+				local_add(reserve_commit_diff,
+					&ltt_buf->commit_count[SUBBUF_INDEX(
+						offset_begin, buf->chan)]);
+				local_inc(&ltt_buf->corrupted_subbuffers);
+			}
+		}
+	}
+
+	/* Always switch */
+	if (end_switch_old) {
+		/* old subbuffer */
+		/* Concurrency safe because we are the last and only thread to
+		 * alter this sub-buffer. As long as it is not delivered and
+		 * read, no other thread can alter the offset, alter the
+		 * reserve_count or call the client_buffer_end_callback on this
+		 * sub-buffer. The only remaining threads could be the ones
+		 * with pending commits. They will have to do the deliver
+		 * themself.
+		 * Not concurrency safe in overwrite mode.
+		 * We detect corrupted subbuffers with commit and reserve
+		 * counts. We keep a corrupted sub-buffers count and push the
+		 * readers across these sub-buffers. Not concurrency safe if a
+		 * writer is stalled in a subbuffer and another writer switches
+		 * in, finding out it's corrupted. The result will be than the
+		 * old (uncommited) subbuffer will be declared corrupted, and
+		 * that the new subbuffer will be declared corrupted too because
+		 * of the commit count adjustment.
+		 * Offset old should never be 0. */
+		ltt_channel->buffer_end(buf, tsc, offset_old,
+				SUBBUF_INDEX((offset_old-1), buf->chan));
+		/* Must write buffer end before incrementing commit count */
+		smp_wmb();
+		commit_count =
+			local_add_return(buf->chan->subbuf_size
+				- (SUBBUF_OFFSET(offset_old-1, buf->chan) + 1),
+				&ltt_buf->commit_count[SUBBUF_INDEX(
+						offset_old-1, buf->chan)]);
+		if (SUBBUF_OFFSET(commit_count, buf->chan) == 0) {
+			ltt_deliver(buf,
+				SUBBUF_INDEX((offset_old-1), buf->chan), NULL);
+		}
+	}
+
+	if (mode == FORCE_ACTIVE) {
+		/* New sub-buffer */
+		/* This code can be executed unordered : writers may already
+		 * have written to the sub-buffer before this code gets
+		 * executed, caution. */
+		/* The commit makes sure that this code is executed before the
+		 * deliver of this sub-buffer */
+		ltt_channel->buffer_begin(buf, tsc,
+				SUBBUF_INDEX(offset_begin, buf->chan));
+		/* Must write buffer begin before incrementing commit count */
+		smp_wmb();
+		commit_count =
+			local_add_return(ltt_subbuf_header_len(),
+			 &ltt_buf->commit_count[SUBBUF_INDEX(offset_begin,
+				 buf->chan)]);
+		/* Check if the written buffer has to be delivered */
+		if (SUBBUF_OFFSET(commit_count, buf->chan) == 0) {
+			ltt_deliver(buf,
+				SUBBUF_INDEX(offset_begin, buf->chan), NULL);
+		}
+	}
+}
+
+/* LTTng channel flush function.
+ *
+ * Must be called when no tracing is active in the channel, because of
+ * accesses across CPUs. */
+static void ltt_relay_buffer_flush(struct rchan_buf *buf)
+{
+	buf->finalized = 1;
+	ltt_force_switch(buf, FORCE_FLUSH);
+}
+
+static void ltt_relay_async_wakeup_chan(struct ltt_channel_struct *ltt_channel)
+{
+	unsigned int i;
+	struct rchan *rchan = ltt_channel->trans_channel_data;
+
+	for_each_possible_cpu(i) {
+		if (atomic_read(&ltt_channel->buf[i].wakeup_readers) == 1) {
+			atomic_set(&ltt_channel->buf[i].wakeup_readers, 0);
+			wake_up_interruptible(&rchan->buf[i]->read_wait);
+		}
+	}
+}
+
+/* Wake writers :
+ *
+ * This must be done after the trace is removed from the RCU list so that there
+ * are no stalled writers. */
+static void ltt_relay_wake_writers(struct ltt_channel_buf_struct *ltt_buf)
+{
+
+	if (waitqueue_active(&ltt_buf->write_wait))
+		schedule_work(&ltt_buf->wake_writers);
+}
+
+static void ltt_relay_finish_buffer(struct ltt_channel_struct *ltt_channel,
+	unsigned int cpu)
+{
+	struct rchan *rchan = ltt_channel->trans_channel_data;
+	struct ltt_channel_buf_struct *ltt_buf;
+
+	if (rchan->buf[cpu]) {
+		ltt_buf = &ltt_channel->buf[cpu];;
+		ltt_relay_buffer_flush(rchan->buf[cpu]);
+		ltt_relay_wake_writers(ltt_buf);
+	}
+}
+
+
+static void ltt_relay_finish_channel(struct ltt_channel_struct *ltt_channel)
+{
+	unsigned int i;
+
+	for_each_possible_cpu(i) {
+		ltt_relay_finish_buffer(ltt_channel, i);
+	}
+}
+
+static void ltt_relay_remove_channel(struct ltt_channel_struct *channel)
+{
+	struct rchan *rchan = channel->trans_channel_data;
+
+	relay_close(rchan);
+	kref_put(&channel->kref, ltt_relay_release_channel);
+}
+
+/* ltt_relay_reserve_slot
+ *
+ * Atomic slot reservation in a LTTng buffer. It will take care of
+ * sub-buffer switching.
+ *
+ * Parameters:
+ *
+ * @trace : the trace structure to log to.
+ * @ltt_channel : channel structure
+ * @transport_data : data structure specific to ltt relay
+ * @data_size : size of the variable length data to log.
+ * @slot_size : pointer to total size of the slot (out)
+ * @tsc : pointer to the tsc at the slot reservation (out)
+ *
+ * Return : NULL if not enough space, else returns the pointer
+ * 		to the beginning of the reserved slot, aligned for the
+ * 		event header. */
+static void *ltt_relay_reserve_slot(
+		struct ltt_trace_struct *trace,
+		struct ltt_channel_struct *ltt_channel,
+		void **transport_data,
+		size_t data_size,
+		size_t *slot_size,
+		u64 *tsc)
+{
+	struct rchan *rchan = ltt_channel->trans_channel_data;
+	struct rchan_buf *buf = *transport_data = rchan->buf[smp_processor_id()];
+	struct ltt_channel_buf_struct *ltt_buf = &ltt_channel->buf[buf->cpu];
+	long offset_begin, offset_end, offset_old;
+	long begin_switch, end_switch_current, end_switch_old;
+	long reserve_commit_diff = 0;
+	size_t size = 0;
+	size_t before_hdr_pad;
+	long consumed_old, consumed_new;
+	long commit_count;
+
+	if (ltt_nesting[ipipe_processor_id()] > 4) {
+		local_inc(&ltt_buf->events_lost);
+		return NULL;
+	}
+
+	do {
+		offset_old = local_read(&ltt_buf->offset);
+		offset_begin = offset_old;
+		begin_switch = 0;
+		end_switch_current = 0;
+		end_switch_old = 0;
+
+		if (SUBBUF_OFFSET(offset_begin, buf->chan) == 0) {
+			begin_switch = 1; /* For offset_begin */
+		} else {
+			size = ltt_get_header_size(ltt_channel,
+					buf->start + offset_begin,
+					data_size, &before_hdr_pad) + data_size;
+			if ((SUBBUF_OFFSET(offset_begin, buf->chan)+size)
+					> buf->chan->subbuf_size) {
+				end_switch_old = 1;	/* For offset_old */
+				begin_switch = 1;	/* For offset_begin */
+			}
+		}
+		if (begin_switch) {
+			if (end_switch_old) {
+				offset_begin =
+					SUBBUF_ALIGN(offset_begin, buf->chan);
+			}
+			offset_begin = offset_begin +
+				ltt_subbuf_header_len();
+			/* Test new buffer integrity */
+			reserve_commit_diff = SUBBUF_OFFSET(
+				buf->chan->subbuf_size - local_read(
+				&ltt_buf->commit_count[
+						SUBBUF_INDEX(offset_begin,
+						buf->chan)]), buf->chan);
+			if (reserve_commit_diff == 0) {
+				/* Next buffer not corrupted. */
+				if (!ltt_channel->overwrite &&
+					(SUBBUF_TRUNC(offset_begin, buf->chan)
+					- SUBBUF_TRUNC(
+					atomic_long_read(&ltt_buf->consumed),
+					buf->chan))
+					>= rchan->alloc_size) {
+					/* We do not overwrite non consumed
+					 * buffers and we are full : event
+					 * is lost. */
+					local_inc(&ltt_buf->events_lost);
+					return NULL;
+				} else {
+					/* next buffer not corrupted, we are
+					 * either in overwrite mode or the
+					 * buffer is not full. It's safe to
+					 * write in this new subbuffer.*/
+				}
+			} else {
+				/* Next subbuffer corrupted. Force pushing
+				 * reader even in normal mode. It's safe to
+				 * write in this new subbuffer. */
+			}
+			size = ltt_get_header_size(ltt_channel,
+					buf->start + offset_begin,
+					data_size, &before_hdr_pad) + data_size;
+			if ((SUBBUF_OFFSET(offset_begin,buf->chan) + size)
+					> buf->chan->subbuf_size) {
+				/* Event too big for subbuffers, report error,
+				 * don't complete the sub-buffer switch. */
+				local_inc(&ltt_buf->events_lost);
+				return NULL;
+			} else {
+				/* We just made a successful buffer switch and
+				 * the event fits in the new subbuffer. Let's
+				 * write. */
+			}
+		} else {
+			/* Event fits in the current buffer and we are not on a
+			 * switch boundary. It's safe to write */
+		}
+		offset_end = offset_begin + size;
+
+		if ((SUBBUF_OFFSET(offset_end, buf->chan)) == 0) {
+			/* The offset_end will fall at the very beginning of
+			 * the next subbuffer. */
+			end_switch_current = 1;	/* For offset_begin */
+		}
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+		if (begin_switch || end_switch_old || end_switch_current)
+			*tsc = ltt_get_timestamp64();
+		else
+			*tsc = ltt_get_timestamp32();
+#else
+		*tsc = ltt_get_timestamp64();
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+		if (*tsc == 0) {
+			/* Error in getting the timestamp, event lost */
+			local_inc(&ltt_buf->events_lost);
+			return NULL;
+		}
+
+	} while (local_cmpxchg(&ltt_buf->offset, offset_old, offset_end)
+							!= offset_old);
+
+
+	/* Push the reader if necessary */
+	do {
+		consumed_old = atomic_long_read(&ltt_buf->consumed);
+		/* If buffer is in overwrite mode, push the reader consumed
+		 * count if the write position has reached it and we are not
+		 * at the first iteration (don't push the reader farther than
+		 * the writer). This operation can be done concurrently by many
+		 * writers in the same buffer, the writer being at the fartest
+		 * write position sub-buffer index in the buffer being the one
+		 * which will win this loop. */
+		/* If the buffer is not in overwrite mode, pushing the reader
+		 * only happen if a sub-buffer is corrupted */
+		if ((SUBBUF_TRUNC(offset_end-1, buf->chan)
+					- SUBBUF_TRUNC(consumed_old, buf->chan))
+					>= rchan->alloc_size)
+			consumed_new = SUBBUF_ALIGN(consumed_old, buf->chan);
+		else {
+			consumed_new = consumed_old;
+			break;
+		}
+	} while (atomic_long_cmpxchg(&ltt_buf->consumed, consumed_old,
+			consumed_new) != consumed_old);
+
+	if (consumed_old != consumed_new) {
+		/* Reader pushed : we are the winner of the push, we can
+		 * therefore reequilibrate reserve and commit. Atomic increment
+		 * of the commit count permits other writers to play around
+		 * with this variable before us. We keep track of
+		 * corrupted_subbuffers even in overwrite mode :
+		 * we never want to write over a non completely committed
+		 * sub-buffer : possible causes : the buffer size is too low
+		 * compared to the unordered data input, or there is a writer
+		 * who died between the reserve and the commit. */
+		if (reserve_commit_diff) {
+			/* We have to alter the sub-buffer commit count : a
+			 * sub-buffer is corrupted. We do not deliver it. */
+			local_add(
+				reserve_commit_diff,
+				&ltt_buf->commit_count[
+					SUBBUF_INDEX(offset_begin, buf->chan)]);
+			local_inc(&ltt_buf->corrupted_subbuffers);
+		}
+	}
+
+	if (end_switch_old) {
+		/* old subbuffer */
+		/* Concurrency safe because we are the last and only thread to
+		 * alter this sub-buffer. As long as it is not delivered and
+		 * read, no other thread can alter the offset, alter the
+		 * reserve_count or call the client_buffer_end_callback on
+		 * this sub-buffer.
+		 * The only remaining threads could be the ones with pending
+		 * commits. They will have to do the deliver themself.
+		 * Not concurrency safe in overwrite mode. We detect corrupted
+		 * subbuffers with commit and reserve counts. We keep a
+		 * corrupted sub-buffers count and push the readers across
+		 * these sub-buffers.
+		 * Not concurrency safe if a writer is stalled in a subbuffer
+		 * and another writer switches in, finding out it's corrupted.
+		 * The result will be than the old (uncommited) subbuffer will
+		 * be declared corrupted, and that the new subbuffer will be
+		 * declared corrupted too because of the commit count
+		 * adjustment.
+		 * Note : offset_old should never be 0 here.*/
+		ltt_channel->buffer_end(buf, *tsc, offset_old,
+			SUBBUF_INDEX((offset_old-1), buf->chan));
+		/* Must write buffer end before incrementing commit count */
+		smp_wmb();
+		commit_count =
+			local_add_return(buf->chan->subbuf_size
+				- (SUBBUF_OFFSET(offset_old-1, buf->chan)+1),
+				&ltt_buf->commit_count[SUBBUF_INDEX(
+						offset_old-1, buf->chan)]);
+		if (SUBBUF_OFFSET(commit_count, buf->chan) == 0) {
+			ltt_deliver(buf, SUBBUF_INDEX((offset_old-1),
+						buf->chan), NULL);
+		}
+	}
+
+	if (begin_switch) {
+		/* New sub-buffer */
+		/* This code can be executed unordered : writers may already
+		 * have written to the sub-buffer before this code gets
+		 * executed, caution. */
+		/* The commit makes sure that this code is executed before the
+		 * deliver of this sub-buffer */
+		ltt_channel->buffer_begin(buf, *tsc, SUBBUF_INDEX(offset_begin,
+					buf->chan));
+		commit_count = local_add_return(
+				ltt_subbuf_header_len(),
+				&ltt_buf->commit_count[
+					SUBBUF_INDEX(offset_begin, buf->chan)]);
+		/* Check if the written buffer has to be delivered */
+		if (SUBBUF_OFFSET(commit_count, buf->chan) == 0) {
+			ltt_deliver(buf,
+				SUBBUF_INDEX(offset_begin, buf->chan), NULL);
+		}
+	}
+
+	if (end_switch_current) {
+		/* current subbuffer */
+		/* Concurrency safe because we are the last and only thread to
+		 * alter this sub-buffer. As long as it is not delivered and
+		 * read, no other thread can alter the offset, alter the
+		 * reserve_count or call the client_buffer_end_callback on this
+		 * sub-buffer.
+		 * The only remaining threads could be the ones with pending
+		 * commits. They will have to do the deliver themself.
+		 * Not concurrency safe in overwrite mode. We detect corrupted
+		 * subbuffers with commit and reserve counts. We keep a
+		 * corrupted sub-buffers count and push the readers across
+		 * these sub-buffers.
+		 * Not concurrency safe if a writer is stalled in a subbuffer
+		 * and another writer switches in, finding out it's corrupted.
+		 * The result will be than the old (uncommited) subbuffer will
+		 * be declared corrupted, and that the new subbuffer will be
+		 * declared corrupted too because of the commit count
+		 * adjustment. */
+		ltt_channel->buffer_end(buf, *tsc, offset_end,
+			SUBBUF_INDEX((offset_end-1), buf->chan));
+		/* Must write buffer begin before incrementing commit count */
+		smp_wmb();
+		commit_count =
+			local_add_return(buf->chan->subbuf_size
+				- (SUBBUF_OFFSET(offset_end-1, buf->chan)+1),
+				&ltt_buf->commit_count[SUBBUF_INDEX(
+						offset_end-1, buf->chan)]);
+		if (SUBBUF_OFFSET(commit_count, buf->chan) == 0) {
+			ltt_deliver(buf,
+				SUBBUF_INDEX((offset_end-1), buf->chan), NULL);
+		}
+	}
+
+	*slot_size = size;
+
+	//BUG_ON(*slot_size != (data_size + *before_hdr_pad + *after_hdr_pad + *header_size));
+	//BUG_ON(*slot_size != (offset_end - offset_begin));
+
+	return buf->start + BUFFER_OFFSET(offset_begin, buf->chan)
+		+ before_hdr_pad;
+}
+
+
+/* ltt_relay_commit_slot
+ *
+ * Atomic unordered slot commit. Increments the commit count in the
+ * specified sub-buffer, and delivers it if necessary.
+ *
+ * Parameters:
+ *
+ * @buf : the buffer to commit to.
+ * @reserved : address following the event header.
+ * @slot_size : size of the reserved slot.
+ *
+ */
+static void ltt_relay_commit_slot(
+		struct ltt_channel_struct *ltt_channel,
+		void **transport_data,
+		void *reserved,
+		size_t slot_size)
+{
+	struct rchan_buf *buf = *transport_data;
+	struct ltt_channel_buf_struct *ltt_buf = &ltt_channel->buf[buf->cpu];
+	unsigned int offset_end = reserved - buf->start;
+	long commit_count;
+
+	/* Must write slot data before incrementing commit count */
+	smp_wmb();
+	commit_count = local_add_return(slot_size,
+		&ltt_buf->commit_count[SUBBUF_INDEX(offset_end-1, buf->chan)]);
+	/* Check if all commits have been done */
+	if (SUBBUF_OFFSET(commit_count, buf->chan) == 0)
+		ltt_deliver(buf, SUBBUF_INDEX(offset_end-1, buf->chan), NULL);
+}
+
+/* This is called with preemption disabled when user space has requested
+ * blocking mode.  If one of the active traces has free space below a
+ * specific threshold value, we reenable preemption and block.
+ */
+static int ltt_relay_user_blocking(struct ltt_trace_struct *trace,
+		unsigned int index, size_t data_size, struct user_dbg_data *dbg)
+{
+	struct rchan *rchan;
+	struct ltt_channel_buf_struct *ltt_buf;
+	struct ltt_channel_struct *channel;
+	struct rchan_buf *relay_buf;
+	DECLARE_WAITQUEUE(wait, current);
+
+	channel = ltt_get_channel_from_index(trace, index);
+	rchan = channel->trans_channel_data;
+	relay_buf = rchan->buf[smp_processor_id()];
+	ltt_buf = &channel->buf[smp_processor_id()];
+	/* Check if data is too big for the channel : do not
+	 * block for it */
+	if (LTT_RESERVE_CRITICAL + data_size > relay_buf->chan->subbuf_size)
+		return 0;
+
+	/* If free space too low, we block. We restart from the
+	 * beginning after we resume (cpu id may have changed
+	 * while preemption is active).
+	 */
+	spin_lock(&ltt_buf->full_lock);
+	if (!channel->overwrite &&
+		(dbg->avail_size = (dbg->write = local_read(
+			&channel->buf[relay_buf->cpu].offset))
+		+ LTT_RESERVE_CRITICAL + data_size
+		 - SUBBUF_TRUNC((dbg->read = atomic_long_read(
+		&channel->buf[relay_buf->cpu].consumed)),
+			 		relay_buf->chan))
+			>= rchan->alloc_size) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&ltt_buf->write_wait, &wait);
+		spin_unlock(&ltt_buf->full_lock);
+		preempt_enable();
+		schedule();
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue(&ltt_buf->write_wait, &wait);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		preempt_disable();
+		return 1;
+	}
+	spin_unlock(&ltt_buf->full_lock);
+	return 0;
+}
+
+static void ltt_relay_print_user_errors(struct ltt_trace_struct *trace,
+		unsigned int index, size_t data_size, struct user_dbg_data *dbg)
+{
+	struct rchan *rchan;
+	struct ltt_channel_buf_struct *ltt_buf;
+	struct ltt_channel_struct *channel;
+	struct rchan_buf *relay_buf;
+
+	channel = ltt_get_channel_from_index(trace, index);
+	rchan = channel->trans_channel_data;
+	relay_buf = rchan->buf[smp_processor_id()];
+	ltt_buf = &channel->buf[smp_processor_id()];
+	printk(KERN_ERR "Error in LTT usertrace : "
+	"buffer full : event lost in blocking "
+	"mode. Increase LTT_RESERVE_CRITICAL.\n");
+	printk(KERN_ERR "LTT nesting level is %u.\n",
+		ltt_nesting[smp_processor_id()]);
+	printk(KERN_ERR "LTT avail size %lu.\n",
+		dbg->avail_size);
+	printk(KERN_ERR "avai write : %lu, read : %lu\n",
+			dbg->write, dbg->read);
+	printk(KERN_ERR "LTT cur size %lu.\n",
+		(dbg->write = local_read(
+		&channel->buf[relay_buf->cpu].offset))
+	+ LTT_RESERVE_CRITICAL + data_size
+	 - SUBBUF_TRUNC((dbg->read = atomic_long_read(
+	&channel->buf[relay_buf->cpu].consumed)),
+				relay_buf->chan));
+	printk(KERN_ERR "cur write : %lu, read : %lu\n",
+			dbg->write, dbg->read);
+}
+
+static struct ltt_transport ltt_relay_transport = {
+	.name = "relay",
+	.owner = THIS_MODULE,
+	.ops = {
+		.create_dirs = ltt_relay_create_dirs,
+		.remove_dirs = ltt_relay_remove_dirs,
+		.create_channel = ltt_relay_create_channel,
+		.finish_channel = ltt_relay_finish_channel,
+		.remove_channel = ltt_relay_remove_channel,
+		.wakeup_channel = ltt_relay_async_wakeup_chan,
+		.commit_slot = ltt_relay_commit_slot,
+		.reserve_slot = ltt_relay_reserve_slot,
+		.user_blocking = ltt_relay_user_blocking,
+		.user_errors = ltt_relay_print_user_errors,
+	},
+};
+
+static int __init ltt_relay_init(void)
+{
+	printk(KERN_INFO "LTT : ltt-relay init\n");
+	ltt_root_dentry = debugfs_create_dir(LTT_RELAY_ROOT, NULL);
+	if (ltt_root_dentry == NULL)
+		return -EEXIST;
+
+	ltt_file_operations = relay_file_operations;
+	ltt_file_operations.owner = THIS_MODULE;
+	ltt_file_operations.poll = ltt_poll;
+	ltt_file_operations.ioctl = ltt_ioctl;
+#ifdef CONFIG_COMPAT
+	ltt_file_operations.compat_ioctl = ltt_compat_ioctl;
+#endif //CONFIG_COMPAT
+
+	ltt_transport_register(&ltt_relay_transport);
+
+	return 0;
+}
+
+static void __exit ltt_relay_exit(void)
+{
+	printk(KERN_INFO "LTT : ltt-relay exit\n");
+
+	ltt_transport_unregister(&ltt_relay_transport);
+
+	debugfs_remove(ltt_root_dentry);
+}
+
+module_init(ltt_relay_init);
+module_exit(ltt_relay_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Tracer");
diff --git a/ltt/ltt-serialize.c b/ltt/ltt-serialize.c
new file mode 100644
index 0000000..2b9d1ed
--- /dev/null
+++ b/ltt/ltt-serialize.c
@@ -0,0 +1,486 @@
+/*
+ * ltt-serialize.c
+ *
+ * LTTng serializing code.
+ *
+ * Copyright Mathieu Desnoyers, March 2007.
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <stdarg.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ltt-tracer.h>
+
+static int skip_atoi(const char **s)
+{
+	int i=0;
+
+	while (isdigit(**s))
+		i = i*10 + *((*s)++) - '0';
+	return i;
+}
+
+/* Inspired from vsnprintf */
+/* The serialization format string supports the basic printf format strings.
+ * In addition, it also defines new formats that can be used to serialize
+ * more complex/non portable data structures.
+ *
+ * Serialization specific formats :
+ *
+ * Fixed length struct, union or array.
+ * %*r     expects sizeof(*ptr), ptr
+ * %*.*r   expects sizeof(*ptr), __alignof__(*ptr), ptr
+ *
+ * Variable length sequence
+ * %*.*:*v expects sizeof(*ptr), __alignof__(*ptr), elem_num, ptr
+ *         where elem_num is the number of elements in the sequence
+ *
+ * Callback
+ * %k      callback (taken from the probe data)
+ *
+ * Fixed size integers
+ * %1b     expects uint8_t
+ * %2b     expects uint16_t
+ * %4b     expects uint32_t
+ * %8b     expects uint64_t
+ * %*b     expects sizeof(data), data
+ *         where sizeof(data) is 1, 2, 4 or 8
+ */
+__attribute__((no_instrument_function))
+char *ltt_serialize_data(char *buffer, char *str,
+			struct ltt_serialize_closure *closure,
+			int align,
+			const char *fmt, va_list *args)
+{
+	const char *s;
+	int elem_size;		/* Size of the integer for 'b' */
+				/* Size of the data contained by 'r' */
+	int elem_alignment;	/* Element alignment for 'r' */
+	int elem_num;		/* Number of elements in 'v' */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+				/* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+				/* 't' added for ptrdiff_t */
+
+	for (; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			/* Skip text */
+			continue;
+		}
+
+		/* process flags : ignore standard print formats for now. */
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-':
+				case '+':
+				case ' ':
+				case '#':
+				case '0': goto repeat;
+			}
+
+		/* get element size */
+		elem_size = -1;
+		if (isdigit(*fmt))
+			elem_size = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			elem_size = va_arg(*args, int);
+		}
+
+		/* get the alignment */
+		elem_alignment = -1;
+		if (*fmt == '.') {
+			++fmt;	
+			if (isdigit(*fmt))
+				elem_alignment = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				elem_alignment = va_arg(*args, int);
+			}
+		}
+
+		/* get the number of elements */
+		elem_num = -1;
+		if (*fmt == ':') {
+			++fmt;	
+			if (isdigit(*fmt))
+				elem_num = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				elem_num = va_arg(*args, int);
+			}
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+		    *fmt =='Z' || *fmt == 'z' || *fmt == 't' ||
+		    *fmt == 'S') {
+			qualifier = *fmt;
+			++fmt;
+			if (qualifier == 'l' && *fmt == 'l') {
+				qualifier = 'L';
+				++fmt;
+			}
+		}
+
+		switch (*fmt) {
+			case 'c':
+				if (buffer)
+					*str = (char)va_arg(*args, int);
+				else
+					(void)va_arg(*args, int);
+				str += sizeof(char);
+				continue;
+
+			case 's':
+				s = va_arg(*args, const char *);
+				if ((unsigned long)s < PAGE_SIZE)
+					s = "<NULL>";
+				elem_size = strlen(s)+1;
+				if (buffer)
+					memcpy(str, s, elem_size);
+				str += elem_size;
+				/* Following alignment for genevent
+				 * compatibility */
+				if (align)
+					str += ltt_align((long)str,
+							sizeof(void*));
+				continue;
+
+			case 'p':
+				if (align)
+					str += ltt_align((long)str,
+							sizeof(void*));
+				if (buffer)
+					*(void**)str = va_arg(*args, void *);
+				else
+					(void)va_arg(*args, void *);
+				str += sizeof(void*);
+				continue;
+
+			case 'r':
+				/* For array, struct, union */
+				if (elem_alignment > 0 && align)
+					str += ltt_align((long)str,
+							elem_alignment);
+				s = va_arg(*args, const char *);
+				if (elem_size > 0) {
+					if (buffer)
+						memcpy(str, s, elem_size);
+					str += elem_size;
+				}
+				continue;
+
+			case 'v':
+				/* For sequence */
+				if (align)
+					str += ltt_align((long)str,
+						max((int)sizeof(int),
+						elem_alignment));
+				if (buffer)
+					*(int*)str = elem_num;
+				str += sizeof(int);
+				if (elem_alignment > 0 && align)
+					str += ltt_align((long)str,
+						elem_alignment);
+				s = va_arg(*args, const char *);
+				if (elem_num > 0) {
+					if (buffer)
+						memcpy(str, s,
+							elem_num*elem_size);
+					str += elem_num*elem_size;
+				}
+				/* Following alignment for genevent
+				 * compatibility */
+				if (align)
+					str += ltt_align((long)str,
+							sizeof(void*));
+				continue;
+
+			case 'k':
+				/* For callback */
+				 /* The callback will take as many arguments
+				  * as it needs from args. They won't be
+				  * type verified. */
+				if (closure->cb_idx < LTT_NR_CALLBACKS-1) {
+					ltt_serialize_cb cb;
+					closure->cb_idx++;
+					cb = closure->callbacks[closure->cb_idx];
+					str = cb(buffer, str, closure,
+							align,
+							fmt, args);
+				}
+				continue;
+
+			case 'n':
+				/* FIXME:
+				* What does C99 say about the overflow case
+				* here? */
+				if (qualifier == 'l') {
+					long * ip = va_arg(*args, long *);
+					*ip = (str - buffer);
+				} else if (qualifier == 'Z'
+					|| qualifier == 'z') {
+					size_t * ip = va_arg(*args, size_t *);
+					*ip = (str - buffer);
+				} else {
+					int * ip = va_arg(*args, int *);
+					*ip = (str - buffer);
+				}
+				continue;
+
+			case '%':
+				continue;
+
+			case 'b':
+				if (elem_size < 0)
+					elem_size = 0;
+				if (elem_size > 0 && align)
+					str += ltt_align((long)str, elem_size);
+				switch (elem_size) {
+				case 1:
+					if (buffer)
+						*(int8_t*)str =
+						(int8_t)va_arg(*args, int);
+					else
+						(void)va_arg(*args, int);
+					break;
+				case 2:
+					if (buffer)
+						*(int16_t*)str =
+						(int16_t)va_arg(*args, int);
+					else
+						(void)va_arg(*args, int);
+					break;
+				case 4:
+					if (buffer)
+						*(int32_t*)str =
+						va_arg(*args, int32_t);
+					else
+						(void)va_arg(*args, int32_t);
+					break;
+				case 8:
+					if (buffer)
+						*(int64_t*)str =
+						va_arg(*args, int64_t);
+					else
+						(void)va_arg(*args, int64_t);
+					break;
+				}
+				str += elem_size;
+				continue;
+
+			case 'o':
+			case 'X':
+			case 'x':
+			case 'd':
+			case 'i':
+			case 'u':
+				break;
+
+			default:
+				if (!*fmt)
+					--fmt;
+				continue;
+		}
+		switch (qualifier) {
+		case 'L':
+			if (align)
+				str += ltt_align((long)str, sizeof(long long));
+			if (buffer)
+				*(long long*)str = va_arg(*args, long long);
+			else
+				(void)va_arg(*args, long long);
+			str += sizeof(long long);
+			break;
+		case 'l':
+			if (align)
+				str += ltt_align((long)str, sizeof(long));
+			if (buffer)
+				*(long*)str = va_arg(*args, long);
+			else
+				(void)va_arg(*args, long);
+			str += sizeof(long);
+			break;
+		case 'Z':
+		case 'z':
+			if (align)
+				str += ltt_align((long)str, sizeof(size_t));
+			if (buffer)
+				*(size_t*)str = va_arg(*args, size_t);
+			else
+				(void)va_arg(*args, size_t);
+			str += sizeof(size_t);
+			break;
+		case 't':
+			if (align)
+				str += ltt_align((long)str, sizeof(ptrdiff_t));
+			if (buffer)
+				*(ptrdiff_t*)str = va_arg(*args, ptrdiff_t);
+			else
+				(void)va_arg(*args, ptrdiff_t);
+			str += sizeof(ptrdiff_t);
+			break;
+		case 'h':
+			if (align)
+				str += ltt_align((long)str, sizeof(short));
+			if (buffer)
+				*(short*)str = (short) va_arg(*args, int);
+			else
+				(void)va_arg(*args, int);
+			str += sizeof(short);
+			break;
+		default:
+			if (align)
+				str += ltt_align((long)str, sizeof(int));
+			if (buffer)
+				*(int*)str = va_arg(*args, int);
+			else
+				(void)va_arg(*args, int);
+			str += sizeof(int);
+		}
+	}
+	return str;
+}
+EXPORT_SYMBOL_GPL(ltt_serialize_data);
+
+/* Calculate data size */
+/* Assume that the padding for alignment starts at a
+ * sizeof(void *) address. */
+static __attribute__((no_instrument_function))
+size_t ltt_get_data_size(struct ltt_serialize_closure *closure,
+				int align,
+				const char *fmt, va_list *args)
+{
+	ltt_serialize_cb cb = closure->callbacks[0];
+	closure->cb_idx = 0;
+	return (size_t)cb(NULL, NULL, closure, align, fmt, args);
+}
+
+static __attribute__((no_instrument_function))
+void ltt_write_event_data(char *buffer,
+				struct ltt_serialize_closure *closure,
+				int align,
+				const char *fmt, va_list *args)
+{
+	ltt_serialize_cb cb = closure->callbacks[0];
+	closure->cb_idx = 0;
+	cb(buffer, buffer, closure, align, fmt, args);
+}
+
+
+__attribute__((no_instrument_function))
+void ltt_vtrace(const struct __mark_marker_data *mdata,
+		const char *fmt, va_list args)
+{
+	int flags;
+	int align;
+	struct ltt_probe_data *pdata;
+	uint8_t fID, eID;
+	size_t data_size, slot_size;
+	int channel_index;
+	struct ltt_channel_struct *channel;
+	struct ltt_trace_struct *trace, *dest_trace = NULL;
+	void *transport_data;
+	uint64_t tsc;
+	char *buffer;
+	va_list args_copy;
+	struct ltt_serialize_closure closure;
+	unsigned long irqflags;
+
+	flags = mdata->flags;
+	pdata = (struct ltt_probe_data *)mdata->pdata;
+	fID = pdata->fID;
+	eID = pdata->eID;
+	align = pdata->align;
+	closure.callbacks = pdata->callbacks;
+
+	/* This test is useful for quickly exiting static tracing when no
+	 * trace is active. */
+	if (likely(ltt_traces.num_active_traces == 0
+		&& !(flags & ltt_flag_mask(LTT_FLAG_FORCE))))
+		return;
+
+	ipipe_preempt_disable(irqflags);
+	ltt_nesting[ipipe_processor_id()]++;
+	
+	if (unlikely(flags & ltt_flag_mask(LTT_FLAG_TRACE)))
+		dest_trace = va_arg(args, struct ltt_trace_struct *);
+	if (unlikely(flags & ltt_flag_mask(LTT_FLAG_CHANNEL)))
+		channel_index = va_arg(args, int);
+	else
+		channel_index = pdata->channel_index;
+	/* Force write in the compact channel if compact flag is used */
+	if (unlikely(flags & ltt_flag_mask(LTT_FLAG_COMPACT)))
+		channel_index = GET_CHANNEL_INDEX(compact);
+
+	va_copy(args_copy, args);
+	/* Skip the compact data for size calculation */
+	if (likely(flags & ltt_flag_mask(LTT_FLAG_COMPACT_DATA)))
+		(void)va_arg(args_copy, u32);
+	data_size = ltt_get_data_size(&closure, align, fmt, &args_copy);
+	va_end(args_copy);
+
+	/* Iterate on each traces */
+	list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
+		if (unlikely(!trace->active
+			&& !(flags & ltt_flag_mask(LTT_FLAG_FORCE))))
+			continue;
+		if (unlikely(flags & ltt_flag_mask(LTT_FLAG_TRACE)
+			&& trace != dest_trace))
+			continue;
+		if (!ltt_run_filter(trace, fID, eID))
+			continue;
+		channel = ltt_get_channel_from_index(trace, channel_index);
+		/* reserve space : header and data */
+		buffer = ltt_reserve_slot(trace, channel, &transport_data,
+						data_size, &slot_size, &tsc);
+		if (unlikely(!buffer))
+			continue; /* buffer full */
+
+		va_copy(args_copy, args);
+		/* Out-of-order write : header and data */
+		if (likely(!(flags & ltt_flag_mask(LTT_FLAG_COMPACT))))
+			buffer = ltt_write_event_header(trace, channel, buffer,
+						fID, eID, data_size, tsc);
+		else {
+			u32 compact_data = 0;
+			if (likely(flags &
+					ltt_flag_mask(LTT_FLAG_COMPACT_DATA)))
+				compact_data = va_arg(args_copy, u32);
+			buffer = ltt_write_compact_header(trace, channel,
+						buffer, fID, eID, data_size,
+						tsc, compact_data);
+		}
+		ltt_write_event_data(buffer, &closure, align, fmt, &args_copy);
+		va_end(args_copy);
+		/* Out-of-order commit */
+		ltt_commit_slot(channel, &transport_data, buffer, slot_size);
+	}
+	ltt_nesting[ipipe_processor_id()]--;
+	ipipe_preempt_enable(irqflags);
+}
+EXPORT_SYMBOL_GPL(ltt_vtrace);
+
+__attribute__((no_instrument_function))
+void ltt_trace(const struct __mark_marker_data *mdata, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	ltt_vtrace(mdata, fmt, args);
+	va_end(args);
+}
+EXPORT_SYMBOL_GPL(ltt_trace);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Serializer");
diff --git a/ltt/ltt-statedump.c b/ltt/ltt-statedump.c
new file mode 100644
index 0000000..2ddcc29
--- /dev/null
+++ b/ltt/ltt-statedump.c
@@ -0,0 +1,370 @@
+/* ltt-statedump.c
+ *
+ * Linux Trace Toolkit Kernel State Dump
+ *
+ * Copyright 2005 -
+ * Jean-Hugues Deschenes <jean-hugues.deschenes@polymtl.ca>
+ *
+ * Changes:
+ *	Eric Clement:           Add listing of network IP interface
+ *	Mathieu Desnoyers	Fix kernel threads
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ltt-tracer.h>
+#include <linux/netlink.h>
+#include <linux/inet.h>
+#include <linux/ip.h>
+#include <linux/kthread.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/cpu.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/marker.h>
+
+#define NB_PROC_CHUNK 20
+
+static atomic_t kernel_threads_to_run;
+static struct delayed_work cpu_work[NR_CPUS];
+static struct task_struct *work_wake_task;
+
+enum lttng_thread_type {
+	LTTNG_USER_THREAD = 0,
+	LTTNG_KERNEL_THREAD = 1,
+};
+
+enum lttng_execution_mode {
+	LTTNG_USER_MODE = 0,
+	LTTNG_SYSCALL = 1,
+	LTTNG_TRAP = 2,
+	LTTNG_IRQ = 3,
+	LTTNG_SOFTIRQ = 4,
+	LTTNG_MODE_UNKNOWN = 5,
+};
+
+enum lttng_execution_submode {
+	LTTNG_NONE = 0,
+	LTTNG_UNKNOWN = 1,
+};
+
+enum lttng_process_status {
+	LTTNG_UNNAMED = 0,
+	LTTNG_WAIT_FORK = 1,
+	LTTNG_WAIT_CPU = 2,
+	LTTNG_EXIT = 3,
+	LTTNG_ZOMBIE = 4,
+	LTTNG_WAIT = 5,
+	LTTNG_RUN = 6,
+	LTTNG_DEAD = 7,
+};
+
+enum lttng_interface_state {
+	LTTNG_UP = 0,
+	LTTNG_DOWN = 1,
+};
+
+/* in modules.c */
+extern void list_modules(void);
+
+#ifdef CONFIG_INET
+static void ltt_enumerate_device(struct net_device *dev)
+{
+	struct in_device *in_dev;
+	struct in_ifaddr *ifa;
+
+	if (dev->flags & IFF_UP) {	
+		in_dev = in_dev_get(dev);
+		if (in_dev) {
+			for (ifa = in_dev->ifa_list;
+					ifa != NULL;
+					ifa = ifa->ifa_next) {
+				MARK(list_network_ip_interface, "%s %4b %d",
+					dev->name, ifa->ifa_address, LTTNG_UP);
+			}
+			in_dev_put(in_dev);		
+		}
+	} else
+		MARK(list_network_ip_interface, "%s %4b %d",
+			dev->name, 0, LTTNG_DOWN);
+}
+
+static inline int ltt_enumerate_network_ip_interface(void)
+{
+	struct net_device *list;
+	
+	read_lock(&dev_base_lock);
+	for (list = dev_base; list != NULL; list = list->next)
+		ltt_enumerate_device(list);
+	read_unlock(&dev_base_lock);
+	
+	return 0;
+}
+#else /* CONFIG_INET */
+static inline int ltt_enumerate_network_ip_interface(void)
+{
+	return 0;
+}
+#endif /* CONFIG_INET */
+
+
+static inline void ltt_enumerate_task_fd(struct task_struct *t,
+		char *tmp)
+{
+	struct fdtable *fdt;
+	struct file * filp;
+	unsigned int i;
+	const unsigned char *path;
+
+	if (!t->files)
+		return;
+
+	spin_lock(&t->files->file_lock);
+	fdt = files_fdtable(t->files);
+	for (i = 0; i < fdt->max_fds; i++) {
+		filp = fcheck_files(t->files, i);
+		if (!filp)
+			continue;
+		path = d_path(filp->f_dentry,
+				filp->f_vfsmnt, tmp, PAGE_SIZE);
+		/* Make sure we give at least some info */
+		MARK(list_file_descriptor, "%s %d %u",
+			(IS_ERR(path))?(filp->f_dentry->d_name.name):(path),
+			t->pid, i);
+	}
+	spin_unlock(&t->files->file_lock);
+}
+
+static inline int ltt_enumerate_file_descriptors(void)
+{
+	struct task_struct * t = &init_task;
+	char *tmp = (char*)__get_free_page(GFP_KERNEL);
+
+	/* Enumerate active file descriptors */
+	do {
+		read_lock(&tasklist_lock);
+		if (t != &init_task)
+			atomic_dec(&t->usage);
+		t = next_task(t);
+		atomic_inc(&t->usage);
+		read_unlock(&tasklist_lock);
+		task_lock(t);
+		ltt_enumerate_task_fd(t, tmp);
+		task_unlock(t);
+	} while (t != &init_task);
+	free_page((unsigned long)tmp);
+	return 0;
+}
+
+static inline void ltt_enumerate_task_vm_maps(struct task_struct *t)
+{
+	struct mm_struct *mm;
+	struct vm_area_struct *	map;
+	unsigned long ino;
+
+	/* get_task_mm does a task_lock... */
+	mm = get_task_mm(t);
+	if (!mm)
+		return;
+
+	map = mm->mmap;
+	if (map) {
+		down_read(&mm->mmap_sem);
+		while (map) {
+			if (map->vm_file)
+				ino = map->vm_file->f_dentry->d_inode->i_ino;
+			else
+				ino = 0;
+			MARK(list_vm_map, "%d %lu %lu %lu %lu %lu",
+					t->pid,
+					map->vm_start,
+					map->vm_end,
+					map->vm_flags,
+					map->vm_pgoff << PAGE_SHIFT,
+					ino);
+			map = map->vm_next;
+		}
+		up_read(&mm->mmap_sem);
+	}
+	mmput(mm);
+}
+
+static inline int ltt_enumerate_vm_maps(void)
+{
+	struct task_struct *  t = &init_task;
+	
+	do {
+		read_lock(&tasklist_lock);
+		if (t != &init_task)
+			atomic_dec(&t->usage);
+		t = next_task(t);
+		atomic_inc(&t->usage);
+		read_unlock(&tasklist_lock);
+		ltt_enumerate_task_vm_maps(t);
+ 	} while (t != &init_task);
+	return 0;
+}
+
+static inline void list_interrupts(void)
+{
+	unsigned int i;
+	unsigned long flags = 0;
+
+	/* needs irq_desc */
+	for (i = 0; i < NR_IRQS; i++) {
+		struct irqaction * action;
+		const char *irq_chip_name =
+			irq_desc[i].chip->name ? : "unnamed_irq_chip";
+
+		spin_lock_irqsave(&irq_desc[i].lock, flags);
+		for (action = irq_desc[i].action;
+			action; action = action->next) {
+			MARK(list_interrupt, "%s %s %u",
+				irq_chip_name, action->name, i);
+		}
+		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+	}
+}
+
+static inline int ltt_enumerate_process_states(void)
+{
+	struct task_struct *t = &init_task;
+	struct task_struct *p = t;
+	enum lttng_process_status status;
+	enum lttng_thread_type type;
+	enum lttng_execution_mode mode;
+	enum lttng_execution_submode submode;
+	
+	do {
+		mode = LTTNG_MODE_UNKNOWN;
+		submode = LTTNG_UNKNOWN;
+
+		read_lock(&tasklist_lock);
+		if (t != &init_task) {
+			atomic_dec(&t->usage);
+			t = next_thread(t);
+		}
+		if (t == p) {
+			t = p = next_task(t);
+		}
+		atomic_inc(&t->usage);
+		read_unlock(&tasklist_lock);
+		
+		task_lock(t);
+		
+		if (t->exit_state == EXIT_ZOMBIE)
+			status = LTTNG_ZOMBIE;
+		else if (t->exit_state == EXIT_DEAD)
+			status = LTTNG_DEAD;
+		else if (t->state == TASK_RUNNING) {
+			/* Is this a forked child that has not run yet? */
+			if (list_empty(&t->run_list))
+				status = LTTNG_WAIT_FORK;
+			else
+				/* All tasks are considered as wait_cpu;
+				 * the viewer will sort out if the task was
+				 * really running at this time. */
+				status = LTTNG_WAIT_CPU;
+		}
+		else if (t->state & 
+			(TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)) {
+			/* Task is waiting for something to complete */
+			status = LTTNG_WAIT;
+		}
+		else
+			status = LTTNG_UNNAMED;
+		submode = LTTNG_NONE;
+
+		/* Verification of t->mm is to filter out kernel threads;
+		 * Viewer will further filter out if a user-space thread was
+		 * in syscall mode or not */
+		if (t->mm)
+			type = LTTNG_USER_THREAD;
+		else
+			type = LTTNG_KERNEL_THREAD;
+			
+		MARK(list_process_state, "%d %d %s %d %d %d %d %d",
+				t->pid, t->parent->pid, t->comm,
+				type, mode, submode, status, t->tgid);
+		task_unlock(t);
+	} while (t != &init_task);
+
+	return 0;
+}
+
+void ltt_statedump_work_func(struct work_struct *work)
+{
+	if (atomic_dec_and_test(&kernel_threads_to_run)) {
+		/* If we are the last thread, wake up do_ltt_statedump */
+		wake_up_process(work_wake_task);
+	}
+}
+
+static int do_ltt_statedump(void)
+{
+	int cpu;
+
+	printk(KERN_DEBUG "do_ltt_statedump\n");
+ 	ltt_enumerate_process_states();
+	ltt_enumerate_file_descriptors();
+	list_modules();
+	ltt_enumerate_vm_maps();
+	list_interrupts();
+	ltt_enumerate_network_ip_interface();
+	
+	/* Fire off a work queue on each CPU. Their sole purpose in life
+	 * is to guarantee that each CPU has been in a state where is was in
+	 * syscall mode (i.e. not in a trap, an IRQ or a soft IRQ) */
+	lock_cpu_hotplug();
+	atomic_set(&kernel_threads_to_run, num_online_cpus());
+	work_wake_task = current;
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	for_each_online_cpu(cpu) {
+		INIT_DELAYED_WORK(&cpu_work[cpu], ltt_statedump_work_func);
+		schedule_delayed_work_on(cpu,&cpu_work[cpu],0);
+	}
+	unlock_cpu_hotplug();
+	/* Wait for all threads to run */
+	schedule();
+	BUG_ON(atomic_read(&kernel_threads_to_run) != 0);
+	/* Our work is done */
+	printk(KERN_DEBUG "do_ltt_statedump end\n");
+	MARK(list_statedump_end, MARK_NOARGS);
+	return 0;
+}
+
+int ltt_statedump_start(struct ltt_trace_struct *trace)
+{
+	printk(KERN_DEBUG "ltt_statedump_start\n");
+
+	return do_ltt_statedump();
+}
+
+/* Dynamic facility. */
+static int __init statedump_init(void)
+{
+	int ret;
+	printk(KERN_INFO "LTT : ltt-facility-statedump init\n");
+	ret = ltt_module_register(LTT_FUNCTION_STATEDUMP,
+			ltt_statedump_start,THIS_MODULE);
+	return ret;
+}
+
+static void __exit statedump_exit(void)
+{
+	printk(KERN_INFO "LTT : ltt-facility-statedump exit\n");
+	ltt_module_unregister(LTT_FUNCTION_STATEDUMP);
+}
+
+module_init(statedump_init)
+module_exit(statedump_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jean-Hugues Deschenes");
+MODULE_DESCRIPTION("Linux Trace Toolkit Statedump");
+
diff --git a/ltt/ltt-syscall.c b/ltt/ltt-syscall.c
new file mode 100644
index 0000000..f9e6f80
--- /dev/null
+++ b/ltt/ltt-syscall.c
@@ -0,0 +1,181 @@
+/******************************************************************************
+ * ltt-syscall.c
+ *
+ * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ * March 2006
+ *
+ * LTT userspace tracing syscalls
+ */
+
+#include <linux/errno.h>
+#include <linux/syscalls.h>
+#include <linux/sched.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+#include <asm/uaccess.h>
+
+/* User event logging function */
+static inline int trace_user_event(unsigned int facility_id,
+		unsigned int event_id,
+		void __user *data, size_t data_size, int blocking,
+		int high_priority)
+{
+	int ret = 0;
+	unsigned int index;
+	struct ltt_channel_struct *channel;
+	struct ltt_trace_struct *trace;
+	void *transport_data;
+	void *buffer = NULL;
+	size_t real_to_base = 0; /* buffer allocated on arch_size alignment */
+	size_t *to_base = &real_to_base;
+	size_t real_to = 0;
+	size_t *to = &real_to;
+	size_t real_len = 0;
+	size_t *len = &real_len;
+	size_t reserve_size;
+	size_t slot_size;
+	u64 tsc;
+	struct user_dbg_data dbg;
+
+	dbg.avail_size = 0;
+	dbg.write = 0;
+	dbg.read = 0;
+
+	if (ltt_traces.num_active_traces == 0)
+		return 0;
+
+	/* Assume that the padding for alignment starts at a
+	 * sizeof(void *) address. */
+
+	reserve_size = data_size;
+
+	if (high_priority)
+		index = GET_CHANNEL_INDEX(processes);
+	else
+		index = GET_CHANNEL_INDEX(cpu);
+
+	preempt_disable();
+
+	if (blocking) {
+		/* User space requested blocking mode :
+		 * If one of the active traces has free space below a specific
+		 * threshold value, we reenable preemption and block. */
+block_test_begin:
+		list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
+			if (!trace->active)
+  				continue;
+
+			if (trace->ops->user_blocking(trace, index, data_size,
+							&dbg))
+ 				goto block_test_begin;
+		}
+	}
+	ltt_nesting[smp_processor_id()]++;
+	list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
+		if (!trace->active)
+			continue;
+		channel = ltt_get_channel_from_index(trace, index);
+		slot_size = 0;
+		buffer = ltt_reserve_slot(trace, channel, &transport_data,
+			reserve_size, &slot_size, &tsc);
+		if (!buffer) {
+			if (blocking)
+				trace->ops->user_errors(trace,
+					index, data_size, &dbg);
+			continue; /* buffer full */
+		}
+		*to_base = *to = *len = 0;
+		buffer = ltt_write_event_header(trace, channel, buffer,
+			facility_id, event_id,
+			reserve_size, tsc);
+		/* Hope the user pages are not swapped out. In the rare case
+		 * where it is, the slot will be zeroed and EFAULT returned. */
+		if (__copy_from_user_inatomic(buffer+*to_base+*to, data,
+					data_size))
+			ret = -EFAULT;	/* Data is garbage in the slot */
+		ltt_commit_slot(channel, &transport_data, buffer, slot_size);
+		if (ret != 0)
+			break;
+	}
+	ltt_nesting[smp_processor_id()]--;
+	preempt_enable_no_resched();
+	return ret;
+}
+
+asmlinkage long sys_ltt_trace_generic(unsigned int facility_id,
+		unsigned int event_id,
+		void __user *data,
+		size_t data_size,
+		int blocking,
+		int high_priority)
+{
+	if (!ltt_facility_user_access_ok(facility_id))
+		return -EPERM;
+	if (!access_ok(VERIFY_READ, data, data_size))
+			return -EFAULT;
+	
+	return trace_user_event(facility_id, event_id, data, data_size,
+			blocking, high_priority);
+}
+
+asmlinkage long sys_ltt_register_generic(unsigned int __user *facility_id,
+		const struct user_facility_info __user *info)
+{
+	struct user_facility_info kinfo;
+	int fac_id;
+	unsigned int i;
+
+	/* Check if the process has already registered the maximum number of 
+	 * allowed facilities */
+	if (current->ltt_facilities[LTT_FAC_PER_PROCESS-1] != 0)
+		return -EPERM;
+	
+	if (copy_from_user(&kinfo, info, sizeof(*info)))
+		return -EFAULT;
+
+	/* Verify if facility is already registered */
+	printk(KERN_DEBUG "LTT register generic for %s\n", kinfo.name);
+	fac_id = ltt_facility_verify(LTT_FACILITY_TYPE_USER,
+				kinfo.name,
+				kinfo.num_events,
+				kinfo.checksum,
+				kinfo.int_size,
+				kinfo.long_size,
+				kinfo.pointer_size,
+				kinfo.size_t_size,
+				kinfo.alignment);
+	
+	printk(KERN_DEBUG "LTT verify return %d\n", fac_id);
+	if (fac_id > 0)
+		goto found;
+	
+	fac_id = ltt_facility_register(LTT_FACILITY_TYPE_USER,
+				kinfo.name,
+				kinfo.num_events,
+				kinfo.checksum,
+				kinfo.int_size,
+				kinfo.long_size,
+				kinfo.pointer_size,
+				kinfo.size_t_size,
+				kinfo.alignment);
+
+	printk(KERN_DEBUG "LTT register return %d\n", fac_id);
+	if (fac_id == 0)
+		return -EPERM;
+	if (fac_id < 0)
+		return fac_id;	/* Error */
+found:
+	get_task_struct(current->group_leader);
+	for (i = 0; i < LTT_FAC_PER_PROCESS; i++) {
+		if (current->group_leader->ltt_facilities[i] == 0) {
+			current->group_leader->ltt_facilities[i] =
+				(uint8_t)fac_id;
+			break;
+		}
+	}
+	put_task_struct(current->group_leader);
+	/* Write facility_id */
+	put_user((unsigned int)fac_id, facility_id);
+	return 0;
+}
diff --git a/ltt/ltt-test-tsc.c b/ltt/ltt-test-tsc.c
new file mode 100644
index 0000000..fd1138e
--- /dev/null
+++ b/ltt/ltt-test-tsc.c
@@ -0,0 +1,116 @@
+/* ltt-test-tsc.c
+ *
+ * Test TSC synchronization
+ */
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <asm/timex.h>
+#include <linux/jiffies.h>
+#include <linux/cpu.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/ltt-tracer.h>
+
+/* Workaround for 32 bits arch which does not define this */
+#ifdef CONFIG_X86_32
+#define get_cycles_sync get_cycles
+#endif
+
+#define MAX_CYCLES_DELTA 1000ULL
+
+static DEFINE_PER_CPU(cycles_t, tsc_count) = 0;
+static DECLARE_MUTEX(tscsync_mutex);
+
+static DEFINE_PER_CPU(int, wait_sync);
+static DEFINE_PER_CPU(int, wait_end_sync);
+
+int ltt_tsc_is_sync = 1;
+EXPORT_SYMBOL(ltt_tsc_is_sync);
+cycles_t ltt_last_tsc = 0;
+EXPORT_SYMBOL(ltt_last_tsc);
+
+/* Mark it noinline so we make sure it is not unrolled.
+ * Wait until value is reached. */
+static noinline void tsc_barrier(long wait_cpu, int value)
+{
+	sync_core();
+	per_cpu(wait_sync, smp_processor_id())--;
+	do {
+		barrier();
+	} while(unlikely(per_cpu(wait_sync, wait_cpu) > value));
+	__get_cpu_var(tsc_count) = get_cycles_sync();
+}
+
+/* worker thread called on each CPU.
+ * First wait with interrupts enabled, then wait with interrupt disabled,
+ * for precision. We are already bound to one CPU. */
+static void test_sync(void *arg)
+{
+	long wait_cpu = (long)arg;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	tsc_barrier(wait_cpu, 1); /* Make sure the instructions are in I-CACHE */
+	tsc_barrier(wait_cpu, 0);
+	per_cpu(wait_end_sync, smp_processor_id())--;
+	do {
+		barrier();
+	} while(unlikely(per_cpu(wait_end_sync, wait_cpu) > 0));
+	local_irq_restore(flags);
+}
+
+/* Do loops (making sure no unexpected event changes the timing), keep the
+ * best one. The result of each loop is the highest tsc delta between the
+ * master CPU and the slaves. */
+static int test_tsc_synchronization(void)
+{
+	long cpu, master;
+	cycles_t max_diff = 0, diff, best_loop, worse_loop = 0;
+	int i;
+
+	down(&tscsync_mutex);
+	preempt_disable();
+	master = smp_processor_id();
+	for_each_online_cpu(cpu) {
+		if (master == cpu)
+			continue;
+		best_loop = ULLONG_MAX;
+		for (i = 0; i < 10; i++) {
+			/* Each CPU (master and slave) must decrement the
+			 * wait_sync value twice (one for priming in cache) */
+			//atomic_set(&wait_sync, 4);
+			//atomic_set(&wait_end_sync, 2);
+			per_cpu(wait_sync, master) = 2;
+			per_cpu(wait_sync, cpu) = 2;
+			per_cpu(wait_end_sync, master) = 1;
+			per_cpu(wait_end_sync, cpu) = 1;
+			smp_call_function_single(cpu, test_sync,
+						(void*)master, 1, 0);
+			test_sync((void*)cpu);
+			diff = abs(per_cpu(tsc_count, cpu)
+				- per_cpu(tsc_count, master));
+			best_loop = min(best_loop, diff);
+			worse_loop = max(worse_loop, diff);
+		}
+		max_diff = max(best_loop, max_diff);
+	}
+	preempt_enable();
+	if (max_diff >= MAX_CYCLES_DELTA) {
+		printk(KERN_WARNING
+			"LTTng : Your timestamp counter is not reliable.\n"
+			"See LTTng documentation to find the "
+			"appropriate solution for your architecture.\n");
+		printk("TSC unsynchronized : %llu cycles delta is over "
+			"threshold %llu\n", max_diff, MAX_CYCLES_DELTA);
+	}
+	up(&tscsync_mutex);
+	return max_diff < MAX_CYCLES_DELTA;
+}
+EXPORT_SYMBOL_GPL(test_tsc_synchronization);
+
+static int __init tsc_test_init(void)
+{
+	ltt_tsc_is_sync = test_tsc_synchronization();
+	return 0;
+}
+__initcall(tsc_test_init);
diff --git a/ltt/ltt-tracer.c b/ltt/ltt-tracer.c
new file mode 100644
index 0000000..46269b2
--- /dev/null
+++ b/ltt/ltt-tracer.c
@@ -0,0 +1,948 @@
+/*
+ * ltt-tracer.c
+ *
+ * (C) Copyright	2005-2006 -
+ * 		Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Contains the kernel code for the Linux Trace Toolkit.
+ *
+ * Author:
+ *	Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
+ *
+ * Inspired from LTT :
+ *	Karim Yaghmour (karim@opersys.com)
+ *	Tom Zanussi (zanussi@us.ibm.com)
+ *	Bob Wisniewski (bob@watson.ibm.com)
+ * And from K42 :
+ *  Bob Wisniewski (bob@watson.ibm.com)
+ *
+ * Changelog:
+ *  22/09/06 Move to the marker/probes mechanism. (Mathieu Desnoyers)
+ *  19/10/05, Complete lockless mechanism. (Mathieu Desnoyers)
+ *	27/05/05, Modular redesign and rewrite. (Mathieu Desnoyers)
+
+ * Comments :
+ * num_active_traces protects the functors. Changing the pointer is an atomic
+ * operation, but the functions can only be called when in tracing. It is then
+ * safe to unload a module in which sits a functor when no tracing is active.
+ *
+ * filter_control functor is protected by incrementing its module refcount.
+ * 
+ */
+
+#include <linux/time.h>
+#include <linux/ltt-tracer.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/ltt-facilities.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/cpu.h>
+#include <linux/kref.h>
+#include <asm/atomic.h>
+
+/* Traces list writer locking */
+DECLARE_MUTEX(ltt_traces_sem);
+
+static struct timer_list ltt_async_wakeup_timer;
+
+/* Default callbacks for modules */
+int ltt_run_filter_default(struct ltt_trace_struct *trace,
+	uint8_t fID, uint8_t eID)
+{
+	return 1;
+}
+
+int ltt_filter_control_default
+	(enum ltt_filter_control_msg msg, struct ltt_trace_struct *trace)
+{
+	return 0;
+}
+
+int ltt_statedump_default(struct ltt_trace_struct *trace)
+{
+	return 0;
+}
+
+
+
+/* Callbacks for registered modules */
+
+int (*ltt_filter_control_functor)
+	(enum ltt_filter_control_msg msg, struct ltt_trace_struct *trace) =
+					ltt_filter_control_default;
+struct module *ltt_filter_control_owner = NULL;
+
+/* These function pointers are protected by trace activation check */
+
+ltt_run_filter_functor ltt_run_filter = ltt_run_filter_default;
+EXPORT_SYMBOL_GPL(ltt_run_filter);
+struct module *ltt_run_filter_owner = NULL;
+
+// FIXME : integrate the filter in the logging chain.
+//
+int (*ltt_statedump_functor)(struct ltt_trace_struct *trace) = 
+					ltt_statedump_default;
+struct module *ltt_statedump_owner = NULL;
+					
+/* Module registration methods */
+
+int ltt_module_register(enum ltt_module_function name, void *function,
+		struct module *owner)
+{
+	int ret = 0;
+	
+	switch (name) {
+		case LTT_FUNCTION_RUN_FILTER:
+			if (ltt_run_filter_owner != NULL) {
+				ret = -EEXIST;
+				goto end;
+			}
+			ltt_run_filter = (ltt_run_filter_functor)function;
+			ltt_run_filter_owner = owner;
+			break;
+		case LTT_FUNCTION_FILTER_CONTROL:
+			if (ltt_filter_control_owner != NULL) {
+				ret = -EEXIST;
+				goto end;
+			}
+			ltt_filter_control_functor = 
+				(int (*)(enum ltt_filter_control_msg,
+				struct ltt_trace_struct *))function;
+			break;
+		case LTT_FUNCTION_STATEDUMP:
+			if (ltt_statedump_owner != NULL) {
+				ret = -EEXIST;
+				goto end;
+			}
+			ltt_statedump_functor = 
+				(int (*)(struct ltt_trace_struct *))function;
+			ltt_statedump_owner = owner;
+			break;
+	}
+
+end:
+
+	return ret;
+}
+
+
+void ltt_module_unregister(enum ltt_module_function name)
+{
+	switch (name) {
+		case LTT_FUNCTION_RUN_FILTER:
+			ltt_run_filter = ltt_run_filter_default;
+			ltt_run_filter_owner = NULL;
+			/* Wait for preempt sections to finish */
+			synchronize_sched();
+			break;
+		case LTT_FUNCTION_FILTER_CONTROL:
+			ltt_filter_control_functor = ltt_filter_control_default;
+			ltt_filter_control_owner = NULL;
+			break;
+		case LTT_FUNCTION_STATEDUMP:
+			ltt_statedump_functor = ltt_statedump_default;
+			ltt_statedump_owner = NULL;
+			break;
+	}
+
+}
+
+EXPORT_SYMBOL_GPL(ltt_module_register);
+EXPORT_SYMBOL_GPL(ltt_module_unregister);
+
+static LIST_HEAD(ltt_transport_list);
+
+void ltt_transport_register(struct ltt_transport *transport)
+{
+	down(&ltt_traces_sem);
+	list_add_tail(&transport->node, &ltt_transport_list);
+	up(&ltt_traces_sem);
+}
+
+void ltt_transport_unregister(struct ltt_transport *transport)
+{
+	down(&ltt_traces_sem);
+	list_del(&transport->node);
+	up(&ltt_traces_sem);
+}
+
+EXPORT_SYMBOL_GPL(ltt_transport_register);
+EXPORT_SYMBOL_GPL(ltt_transport_unregister);
+
+
+static inline int is_channel_overwrite(enum ltt_channels chan,
+	enum trace_mode mode)
+{
+	switch (mode) {
+		case LTT_TRACE_NORMAL:
+			return 0;
+		case LTT_TRACE_FLIGHT:
+			switch (chan) {
+				case LTT_CHANNEL_FACILITIES:
+					return 0;
+				default:
+					return 1;
+			}
+		case LTT_TRACE_HYBRID:
+			switch (chan) {
+				case LTT_CHANNEL_CPU:
+					return 1;
+				default:
+					return 0;
+			}
+		default:
+			return 0;
+	}
+}
+
+
+void ltt_write_trace_header(struct ltt_trace_struct *trace,
+		struct ltt_trace_header *header)
+{
+	header->magic_number = LTT_TRACER_MAGIC_NUMBER;
+	header->major_version = LTT_TRACER_VERSION_MAJOR;
+	header->minor_version = LTT_TRACER_VERSION_MINOR;
+	header->float_word_order = 0;	 /* Kernel : no floating point */
+	header->arch_type = LTT_ARCH_TYPE;
+	header->arch_size = sizeof(void*);
+	header->arch_variant = LTT_ARCH_VARIANT;
+	switch (trace->mode) {
+		case LTT_TRACE_NORMAL:
+			header->flight_recorder = 0;
+			break;
+		case LTT_TRACE_FLIGHT:
+			header->flight_recorder = 1;
+			break;
+		case LTT_TRACE_HYBRID:
+			header->flight_recorder = 2;
+			break;
+		default:
+			header->flight_recorder = 0;
+	}
+	
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	header->has_heartbeat = 1;
+	header->tsc_lsb_truncate = ltt_tsc_lsb_truncate;
+	header->tscbits = ltt_tscbits;
+#else
+	header->has_heartbeat = 0;
+	header->tsc_lsb_truncate = 0;
+	header->tscbits = 32;
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+
+#ifdef CONFIG_LTT_ALIGNMENT
+	header->has_alignment = sizeof(void*);
+#else
+	header->has_alignment = 0;
+#endif
+	header->freq_scale = trace->freq_scale;
+	header->start_freq = trace->start_freq;
+	header->start_tsc = trace->start_tsc;
+	header->start_monotonic = trace->start_monotonic;
+	header->start_time_sec = trace->start_time.tv_sec;
+	header->start_time_usec = trace->start_time.tv_usec;
+}
+EXPORT_SYMBOL_GPL(ltt_write_trace_header);
+
+static void trace_async_wakeup(struct ltt_trace_struct *trace)
+{
+	/* Must check each channel for pending read wakeup */
+	trace->ops->wakeup_channel(trace->channel.facilities);
+	trace->ops->wakeup_channel(trace->channel.interrupts);
+	trace->ops->wakeup_channel(trace->channel.processes);
+	trace->ops->wakeup_channel(trace->channel.modules);
+	trace->ops->wakeup_channel(trace->channel.network);
+	trace->ops->wakeup_channel(trace->channel.cpu);
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	trace->ops->wakeup_channel(trace->channel.compact);
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+}
+
+/* Timer to send async wakeups to the readers */
+static void async_wakeup(unsigned long data)
+{
+	struct ltt_trace_struct *trace;
+	preempt_disable();
+	list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
+		trace_async_wakeup(trace);
+	}
+	preempt_enable();
+
+	del_timer(&ltt_async_wakeup_timer);
+	ltt_async_wakeup_timer.expires = jiffies + LTT_PERCPU_TIMER_INTERVAL;
+	add_timer(&ltt_async_wakeup_timer);
+}
+
+
+
+
+void ltt_wakeup_writers(struct work_struct *work)
+{
+	struct ltt_channel_buf_struct *ltt_buf =
+		container_of(work, struct ltt_channel_buf_struct, wake_writers);
+	
+	wake_up_interruptible(&ltt_buf->write_wait);
+}
+EXPORT_SYMBOL_GPL(ltt_wakeup_writers);
+
+
+/* _ltt_trace_find :
+ * find a trace by given name.
+ *
+ * Returns a pointer to the trace structure, NULL if not found. */
+static struct ltt_trace_struct *_ltt_trace_find(char *trace_name)
+{
+	int compare;
+	struct ltt_trace_struct *trace, *found=NULL;
+	
+	list_for_each_entry(trace, &ltt_traces.head, list) {
+		compare = strncmp(trace->trace_name, trace_name, NAME_MAX);
+
+		if (compare == 0) {
+			found = trace;
+			break;
+		}
+	}
+	
+	return found;
+}
+
+/* This function must be called with traces semaphore held. */
+static int _ltt_trace_create(char *trace_name,	enum trace_mode mode,
+				struct ltt_trace_struct *new_trace)
+{
+	int err = EPERM;
+
+	if (_ltt_trace_find(trace_name) != NULL) {
+		printk(KERN_ERR "LTT : Trace %s already exists\n", trace_name);
+		err = EEXIST;
+		goto traces_error;
+	}
+	list_add_rcu(&new_trace->list, &ltt_traces.head);
+	synchronize_sched();
+	/* Everything went fine, finish creation */
+	return 0;
+
+	/* Error handling */
+traces_error:
+	return err;
+}
+
+
+void ltt_release_transport(struct kref *kref)
+{
+	struct ltt_trace_struct *trace = container_of(kref,
+			struct ltt_trace_struct, ltt_transport_kref);
+	trace->ops->remove_dirs(trace);
+}
+EXPORT_SYMBOL_GPL(ltt_release_transport);
+
+
+void ltt_release_trace(struct kref *kref)
+{
+	struct ltt_trace_struct *trace = container_of(kref,
+			struct ltt_trace_struct, kref);
+	kfree(trace);
+}
+EXPORT_SYMBOL_GPL(ltt_release_trace);
+
+static inline void prepare_chan_size_num(unsigned *subbuf_size,
+	unsigned *n_subbufs, unsigned default_size, unsigned default_n_subbufs)
+{
+	if (*subbuf_size == 0)
+		*subbuf_size = default_size;
+	if (*n_subbufs == 0)
+		*n_subbufs = default_n_subbufs;
+	*subbuf_size = 1 << get_count_order(*subbuf_size);
+	*n_subbufs = 1 << get_count_order(*n_subbufs);
+
+	/* Subbuf size and number must both be power of two */
+	WARN_ON(hweight32(*subbuf_size) != 1);
+	WARN_ON(hweight32(*n_subbufs) != 1);
+}
+
+static int ltt_trace_create(char *trace_name, char *trace_type,
+		enum trace_mode mode,
+		unsigned subbuf_size_low, unsigned n_subbufs_low,
+		unsigned subbuf_size_med, unsigned n_subbufs_med,
+		unsigned subbuf_size_high, unsigned n_subbufs_high)
+{
+	int err = 0;
+	struct ltt_trace_struct *new_trace, *trace;
+	unsigned long flags;
+	struct ltt_transport *tran, *transport = NULL;
+	
+	prepare_chan_size_num(&subbuf_size_low, &n_subbufs_low,
+		LTT_DEFAULT_SUBBUF_SIZE_LOW, LTT_DEFAULT_N_SUBBUFS_LOW);
+
+	prepare_chan_size_num(&subbuf_size_med, &n_subbufs_med,
+		LTT_DEFAULT_SUBBUF_SIZE_MED, LTT_DEFAULT_N_SUBBUFS_MED);
+
+	prepare_chan_size_num(&subbuf_size_high, &n_subbufs_high,
+		LTT_DEFAULT_SUBBUF_SIZE_HIGH, LTT_DEFAULT_N_SUBBUFS_HIGH);
+
+	new_trace = kzalloc(sizeof(struct ltt_trace_struct), GFP_KERNEL);
+	if (!new_trace) {
+		printk(KERN_ERR
+			"LTT : Unable to allocate memory for trace %s\n",
+			trace_name);
+		err = ENOMEM;
+		goto traces_error;
+	}
+
+	kref_init(&new_trace->kref);
+	kref_init(&new_trace->ltt_transport_kref);
+	new_trace->active = 0;
+	strncpy(new_trace->trace_name, trace_name, NAME_MAX);
+	new_trace->paused = 0;
+	new_trace->mode = mode;
+	new_trace->freq_scale = ltt_freq_scale();
+
+	down(&ltt_traces_sem);
+	list_for_each_entry(tran, &ltt_transport_list, node) {
+		if (!strcmp(tran->name, trace_type)) {
+			transport = tran;
+			break;
+		}
+	}
+
+	if (!transport) {
+		err = EINVAL;
+		printk(KERN_ERR	"LTT : Transport %s is not present.\n", trace_type);
+		up(&ltt_traces_sem);
+		goto trace_error;
+	}
+
+	if (!try_module_get(transport->owner)) {
+		err = ENODEV;
+		printk(KERN_ERR	"LTT : Can't lock transport module.\n");
+		up(&ltt_traces_sem);
+		goto trace_error;
+	}
+
+	trace = _ltt_trace_find(trace_name);
+	if(trace) {
+		printk(KERN_ERR	"LTT : Trace name %s already used.\n",
+			trace_name);
+		err = EEXIST;
+		goto trace_error;
+	}
+
+	new_trace->transport = transport;
+	new_trace->ops = &transport->ops;
+
+	err = new_trace->ops->create_dirs(new_trace);
+	if (err)
+		goto dirs_error;
+
+	local_irq_save(flags);
+	new_trace->start_freq = ltt_frequency();
+	new_trace->start_tsc = ltt_get_timestamp64();
+	do_gettimeofday(&new_trace->start_time);
+	local_irq_restore(flags);
+	
+	/* Always put the facilities channel in non-overwrite mode :
+	 * This is a very low traffic channel and it can't afford to have its
+	 * data overwritten : this data (facilities info) is necessary to be
+	 * able to read the trace.
+	 *
+	 * WARNING : The heartbeat time _shouldn't_ write events in the
+	 * facilities channel as it would make the traffic too high. This is a
+	 * problematic case with flight recorder mode. FIXME
+	 */
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.control_root,
+			LTT_FACILITIES_CHANNEL,
+			&new_trace->channel.facilities, subbuf_size_low,
+			n_subbufs_low,
+			is_channel_overwrite(LTT_CHANNEL_FACILITIES, mode));
+	if (err != 0) {
+		goto facilities_error;
+	}
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.control_root,
+			LTT_INTERRUPTS_CHANNEL,
+			&new_trace->channel.interrupts, subbuf_size_low,
+			n_subbufs_low,
+			is_channel_overwrite(LTT_CHANNEL_INTERRUPTS, mode));
+	if (err != 0) {
+		goto interrupts_error;
+	}
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.control_root,
+			LTT_PROCESSES_CHANNEL,
+			&new_trace->channel.processes, subbuf_size_med,
+			n_subbufs_med,
+			is_channel_overwrite(LTT_CHANNEL_PROCESSES, mode));
+	if (err != 0) {
+		goto processes_error;
+	}
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.control_root,
+			LTT_MODULES_CHANNEL,
+			&new_trace->channel.modules, subbuf_size_low,
+			n_subbufs_low,
+			is_channel_overwrite(LTT_CHANNEL_MODULES, mode));
+	if (err != 0) {
+		goto modules_error;
+	}
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.control_root,
+			LTT_NETWORK_CHANNEL,
+			&new_trace->channel.network, subbuf_size_low,
+			n_subbufs_low,
+			is_channel_overwrite(LTT_CHANNEL_NETWORK, mode));
+	if (err != 0) {
+		goto network_error;
+	}
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.trace_root,
+			LTT_CPU_CHANNEL,
+			&new_trace->channel.cpu, subbuf_size_high,
+			n_subbufs_high,
+			is_channel_overwrite(LTT_CHANNEL_CPU, mode));
+	if (err != 0) {
+		goto cpu_error;
+	}
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	err = new_trace->ops->create_channel(trace_name, new_trace,
+			new_trace->dentry.trace_root,
+			LTT_COMPACT_CHANNEL,
+			&new_trace->channel.compact, subbuf_size_high,
+			n_subbufs_high,
+			is_channel_overwrite(LTT_CHANNEL_COMPACT, mode));
+	if (err != 0) {
+		goto compact_error;
+	}
+#endif
+
+	err = _ltt_trace_create(trace_name, mode, new_trace);
+
+	if (err != 0)
+		goto lock_create_error;
+	up(&ltt_traces_sem);
+	return err;
+
+lock_create_error:
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	new_trace->ops->remove_channel(new_trace->channel.compact);
+compact_error:
+#endif
+	new_trace->ops->remove_channel(new_trace->channel.cpu);
+cpu_error:
+	new_trace->ops->remove_channel(new_trace->channel.network);
+network_error:
+	new_trace->ops->remove_channel(new_trace->channel.modules);
+modules_error:
+	new_trace->ops->remove_channel(new_trace->channel.processes);
+processes_error:
+	new_trace->ops->remove_channel(new_trace->channel.interrupts);
+interrupts_error:
+	new_trace->ops->remove_channel(new_trace->channel.facilities);
+facilities_error:
+	kref_put(&new_trace->ltt_transport_kref, ltt_release_transport);
+dirs_error:
+	module_put(transport->owner);
+trace_error:
+	kref_put(&new_trace->kref, ltt_release_trace);
+	up(&ltt_traces_sem);
+traces_error:
+	return err;
+}
+
+/* Must be called while sure that trace is in the list. */
+static int _ltt_trace_destroy(struct ltt_trace_struct	*trace)
+{
+	int err = EPERM;
+	
+	if (trace == NULL) {
+		err = ENOENT;
+		goto traces_error;
+	}
+	if (trace->active) {
+		printk(KERN_ERR
+			"LTT : Can't destroy trace %s : tracer is active\n",
+			trace->trace_name);
+		err = EBUSY;
+		goto active_error;
+	}
+	/* Everything went fine */
+	list_del_rcu(&trace->list);
+	synchronize_sched();
+	/* If no more trace in the list, we can free the unused facilities */
+	if (list_empty(&ltt_traces.head))
+		ltt_facility_free_unused();
+	return 0;
+
+	/* error handling */
+active_error:
+traces_error:
+	return err;
+}
+
+/* Sleepable part of the destroy */
+static void __ltt_trace_destroy(struct ltt_trace_struct	*trace)
+{
+	trace->ops->finish_channel(trace->channel.facilities);
+	trace->ops->finish_channel(trace->channel.interrupts);
+	trace->ops->finish_channel(trace->channel.processes);
+	trace->ops->finish_channel(trace->channel.modules);
+	trace->ops->finish_channel(trace->channel.network);
+	trace->ops->finish_channel(trace->channel.cpu);
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	trace->ops->finish_channel(trace->channel.compact);
+#endif
+
+	flush_scheduled_work();
+
+	if (ltt_traces.num_active_traces == 0) {
+		/* We stop the asynchronous delivery of reader wakeup, but
+		 * we must make one last check for reader wakeups pending. */
+		del_timer(&ltt_async_wakeup_timer);
+	}
+	/* The currently destroyed trace is not in the trace list anymore,
+	 * so it's safe to call the async wakeup ourself. It will deliver
+	 * the last subbuffers. */
+	trace_async_wakeup(trace);
+
+	trace->ops->remove_channel(trace->channel.facilities);
+	trace->ops->remove_channel(trace->channel.interrupts);
+	trace->ops->remove_channel(trace->channel.processes);
+	trace->ops->remove_channel(trace->channel.modules);
+	trace->ops->remove_channel(trace->channel.network);
+	trace->ops->remove_channel(trace->channel.cpu);
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+	trace->ops->remove_channel(trace->channel.compact);
+#endif
+
+	kref_put(&trace->ltt_transport_kref, ltt_release_transport);
+
+	module_put(trace->transport->owner);
+
+	kref_put(&trace->kref, ltt_release_trace);
+}
+
+static int ltt_trace_destroy(char *trace_name)
+{
+	int err = 0;
+	struct ltt_trace_struct* trace;
+
+	down(&ltt_traces_sem);
+	trace = _ltt_trace_find(trace_name);
+	err = _ltt_trace_destroy(trace);
+	if (err)
+		goto error;
+	up(&ltt_traces_sem);
+	__ltt_trace_destroy(trace);
+	return err;
+
+	/* Error handling */
+error:
+	up(&ltt_traces_sem);
+	return err;
+}
+
+#ifdef CONFIG_LTT_HEARTBEAT_EVENT
+static void full_heartbeat_ipi(void *info)
+{
+	struct ltt_trace_struct* trace = (struct ltt_trace_struct*)info;
+	#define HB_FULL_FLAGS \
+		(_MF_DEFAULT | ltt_flag_mask(LTT_FLAG_TRACE) \
+			| ltt_flag_mask(LTT_FLAG_CHANNEL)\
+			| ltt_flag_mask(LTT_FLAG_FORCE))
+
+	/* Log a heartbeat event for each trace, each tracefile */
+	_MARK(HB_FULL_FLAGS,
+		core_time_heartbeat_full, 
+		"%8b",
+		trace,
+		GET_CHANNEL_INDEX(facilities),
+		ltt_get_timestamp64());
+	_MARK(HB_FULL_FLAGS,
+		core_time_heartbeat_full,
+		"%8b",
+		trace,
+		GET_CHANNEL_INDEX(interrupts),
+		ltt_get_timestamp64());
+	_MARK(HB_FULL_FLAGS,
+		core_time_heartbeat_full,
+		"%8b",
+		trace,
+		GET_CHANNEL_INDEX(processes),
+		ltt_get_timestamp64());
+	_MARK(HB_FULL_FLAGS,
+		core_time_heartbeat_full,
+		"%8b",
+		trace,
+		GET_CHANNEL_INDEX(modules),
+		ltt_get_timestamp64());
+	_MARK(HB_FULL_FLAGS,
+		core_time_heartbeat_full,
+		"%8b",
+		trace,
+		GET_CHANNEL_INDEX(cpu),
+		ltt_get_timestamp64());
+	_MARK(HB_FULL_FLAGS,
+		core_time_heartbeat_full,
+		"%8b",
+		trace,
+		GET_CHANNEL_INDEX(network),
+		ltt_get_timestamp64());
+	_MARK(_MF_DEFAULT
+		| ltt_flag_mask(LTT_FLAG_TRACE)
+		| ltt_flag_mask(LTT_FLAG_COMPACT)
+		| ltt_flag_mask(LTT_FLAG_FORCE),
+		compact_time_heartbeat_full,
+		"%8b",
+		trace,
+		ltt_get_timestamp64());
+#undef HB_FULL_FLAGS
+}
+
+void write_full_tsc(struct ltt_trace_struct* trace)
+{
+	on_each_cpu(full_heartbeat_ipi, trace, 1, 1);
+}
+#else //CONFIG_LTT_HEARTBEAT_EVENT
+void write_full_tsc(struct ltt_trace_struct* trace)
+{
+}
+#endif //CONFIG_LTT_HEARTBEAT_EVENT
+
+/* must be called from within a traces lock. */
+static int _ltt_trace_start(struct ltt_trace_struct* trace)
+{
+	int err = 0;
+
+	if (trace == NULL) {
+		err = ENOENT;
+		goto traces_error;
+	}
+	if (trace->active)
+		printk(KERN_INFO "LTT : Tracing already active for trace %s\n",
+				trace->trace_name);
+	if (!try_module_get(ltt_run_filter_owner)) {
+		err = ENODEV;
+		printk(KERN_ERR "LTT : Can't lock filter module.\n");
+		goto get_ltt_run_filter_error;
+	}
+	if (ltt_traces.num_active_traces == 0) {
+#ifdef CONFIG_LTT_HEARTBEAT
+		if (ltt_heartbeat_trigger(LTT_HEARTBEAT_START)) {
+			err = ENODEV;
+			printk(KERN_ERR
+				"LTT : Heartbeat timer module not present.\n");
+			goto ltt_heartbeat_error;
+		}
+#endif //CONFIG_LTT_HEARTBEAT
+		init_timer(&ltt_async_wakeup_timer);
+		ltt_async_wakeup_timer.function = async_wakeup;
+		ltt_async_wakeup_timer.expires =
+			jiffies + LTT_PERCPU_TIMER_INTERVAL;
+		add_timer(&ltt_async_wakeup_timer);
+	}
+	/* Write a full 64 bits TSC in each trace. Used for successive 
+	 * trace stop/start. */
+	write_full_tsc(trace);
+	trace->active = 1;
+	ltt_traces.num_active_traces++;	/* Read by trace points without
+					 * protection : be careful */
+	return err;
+
+	/* error handling */
+#ifdef CONFIG_LTT_HEARTBEAT
+ltt_heartbeat_error:
+#endif //CONFIG_LTT_HEARTBEAT
+	module_put(ltt_run_filter_owner);
+get_ltt_run_filter_error:
+traces_error:
+	return err;
+}
+
+static int ltt_trace_start(char *trace_name)
+{
+	int err = 0;
+	struct ltt_trace_struct* trace;
+
+	down(&ltt_traces_sem);
+
+	trace = _ltt_trace_find(trace_name);
+	if (trace == NULL)
+		goto no_trace;
+	err = _ltt_trace_start(trace);
+
+	up(&ltt_traces_sem);
+	
+	/* Call the kernel state dump.
+	 * Events will be mixed with real kernel events, it's ok.
+	 * Notice that there is no protection on the trace : that's exactly
+	 * why we iterate on the list and check for trace equality instead of
+	 * directly using this trace handle inside the logging function. */
+	
+	ltt_facility_state_dump(trace);
+
+	if (!try_module_get(ltt_statedump_owner)) {
+		err = ENODEV;
+		printk(KERN_ERR
+			"LTT : Can't lock state dump module.\n");
+	} else {
+		ltt_statedump_functor(trace);
+		module_put(ltt_statedump_owner);
+	}
+
+	return err;
+
+	/* Error handling */
+no_trace:
+	up(&ltt_traces_sem);
+	return err;
+}
+
+
+/* must be called from within traces lock */
+static int _ltt_trace_stop(struct ltt_trace_struct* trace)
+{
+	int err = EPERM;
+
+	if (trace == NULL) {
+		err = ENOENT;
+		goto traces_error;
+	}
+	if (!trace->active)
+		printk(KERN_INFO "LTT : Tracing not active for trace %s\n",
+				trace->trace_name);
+	if (trace->active) {
+		trace->active = 0;
+		ltt_traces.num_active_traces--;
+		synchronize_sched(); /* Wait for each tracing to be finished */
+	}
+	if (ltt_traces.num_active_traces == 0) {
+#ifdef CONFIG_LTT_HEARTBEAT
+	/* stop the heartbeat if we are the last active trace */
+		ltt_heartbeat_trigger(LTT_HEARTBEAT_STOP);
+#endif //CONFIG_LTT_HEARTBEAT
+	}
+	module_put(ltt_run_filter_owner);
+	/* Everything went fine */
+	return 0;
+
+	/* Error handling */
+traces_error:
+	return err;
+}
+
+static int ltt_trace_stop(char *trace_name)
+{
+	int err = 0;
+	struct ltt_trace_struct* trace;
+
+	down(&ltt_traces_sem);
+	trace = _ltt_trace_find(trace_name);
+	err = _ltt_trace_stop(trace);
+	up(&ltt_traces_sem);
+	return err;
+}
+
+
+/* Exported functions */
+
+int ltt_control(enum ltt_control_msg msg, char *trace_name, char *trace_type,
+		union ltt_control_args args)
+{
+	int err = EPERM;
+	
+	printk(KERN_ALERT "ltt_control : trace %s\n", trace_name);
+	switch (msg) {
+		case LTT_CONTROL_START:
+			printk(KERN_DEBUG "Start tracing %s\n", trace_name);
+			err = ltt_trace_start(trace_name);
+			break;
+		case LTT_CONTROL_STOP:
+			printk(KERN_DEBUG "Stop tracing %s\n", trace_name);
+			err = ltt_trace_stop(trace_name);
+			break;
+		case LTT_CONTROL_CREATE_TRACE:
+			printk(KERN_DEBUG "Creating trace %s\n", trace_name);
+			err = ltt_trace_create(trace_name, trace_type,
+				args.new_trace.mode,
+				args.new_trace.subbuf_size_low,
+				args.new_trace.n_subbufs_low,
+				args.new_trace.subbuf_size_med,
+				args.new_trace.n_subbufs_med,
+				args.new_trace.subbuf_size_high,
+				args.new_trace.n_subbufs_high);
+			break;
+		case LTT_CONTROL_DESTROY_TRACE:
+			printk(KERN_DEBUG "Destroying trace %s\n", trace_name);
+			err = ltt_trace_destroy(trace_name);
+			break;
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(ltt_control);
+
+int ltt_filter_control(enum ltt_filter_control_msg msg, char *trace_name)
+{
+	int err;
+	struct ltt_trace_struct *trace;
+
+	printk(KERN_DEBUG "ltt_filter_control : trace %s\n", trace_name);
+	down(&ltt_traces_sem);
+	trace = _ltt_trace_find(trace_name);
+	if (trace == NULL) {
+		printk(KERN_ALERT
+			"Trace does not exist. Cannot proxy control request\n");
+		err = ENOENT;
+		goto trace_error;
+	}
+	if (!try_module_get(ltt_filter_control_owner)) {
+		err = ENODEV;
+		goto get_module_error;
+	}
+	switch (msg) {
+		case LTT_FILTER_DEFAULT_ACCEPT:
+			printk(KERN_DEBUG
+				"Proxy filter default accept %s\n", trace_name);
+			err = (*ltt_filter_control_functor)(msg, trace);
+			break;
+		case LTT_FILTER_DEFAULT_REJECT:
+			printk(KERN_DEBUG
+				"Proxy filter default reject %s\n", trace_name);
+			err = (*ltt_filter_control_functor)(msg, trace);
+			break;
+		default:
+			err = EPERM;
+	}
+	module_put(ltt_filter_control_owner);
+	
+get_module_error:
+trace_error:
+	up(&ltt_traces_sem);
+	return err;
+}
+EXPORT_SYMBOL_GPL(ltt_filter_control);
+
+static void __exit ltt_exit(void)
+{
+	struct ltt_trace_struct *trace;
+	
+	down(&ltt_traces_sem);
+	/* Stop each trace and destroy them */
+	list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
+		_ltt_trace_stop(trace);
+		_ltt_trace_destroy(trace);/* it's doing a synchronize_sched() */
+		__ltt_trace_destroy(trace);
+	}
+	up(&ltt_traces_sem);
+}
+
+module_exit(ltt_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Tracer");
diff --git a/ltt/probes/Makefile b/ltt/probes/Makefile
new file mode 100644
index 0000000..8aa2373
--- /dev/null
+++ b/ltt/probes/Makefile
@@ -0,0 +1,14 @@
+# LTT probes makefile
+
+obj-$(CONFIG_LTT_PROBE_CORE)	+= ltt-probe-core.o
+obj-$(CONFIG_LTT_PROBE_COMPACT)	+= ltt-probe-compact.o
+obj-$(CONFIG_LTT_PROBE_FS)	+= ltt-probe-fs.o
+obj-$(CONFIG_LTT_PROBE_ARCH)	+= \
+			ltt-probe-kernel_arch_$(ARCH).o
+obj-$(CONFIG_LTT_PROBE_KERNEL)	+= ltt-probe-kernel.o
+obj-$(CONFIG_LTT_PROBE_LIST)	+= ltt-probe-list.o
+obj-$(CONFIG_LTT_PROBE_MM)	+= ltt-probe-mm.o
+obj-$(CONFIG_LTT_PROBE_NET)	+= ltt-probe-net.o
+obj-$(CONFIG_LTT_PROBE_LOCKING)	+= ltt-probe-locking.o
+obj-$(CONFIG_LTT_PROBE_STACK)	+= ltt-probe-stack_arch_$(ARCH).o
+obj-$(CONFIG_LTT_PROBE_XENOMAI)	+= ltt-probe-xenomai.o
diff --git a/ltt/probes/ltt-probe-compact.c b/ltt/probes/ltt-probe-compact.c
new file mode 100644
index 0000000..9b7b44e
--- /dev/null
+++ b/ltt/probes/ltt-probe-compact.c
@@ -0,0 +1,124 @@
+/*
+ * ltt-probe-compact.c
+ *
+ * compact probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "compact"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "compact_time_heartbeat", MARK_NOARGS },
+	{ "compact_time_heartbeat_full", "%8b" },
+	{ "compact_event_a", MARK_NOARGS, GET_CHANNEL_INDEX(compact) },
+	{ "compact_event_b", "%4b", GET_CHANNEL_INDEX(compact) },
+	{ "compact_event_c", "%8b", GET_CHANNEL_INDEX(compact) },
+	{ "compact_event_d", MARK_NOARGS, GET_CHANNEL_INDEX(compact) },
+	{ "compact_event_e", "%8b", GET_CHANNEL_INDEX(compact) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 0,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	/* First write a full heartbeat */
+	eID = 1;
+	probe_array[eID].fID = facility.id;
+	probe_array[eID].eID = eID;
+	probe_array[eID].align = facility.alignment;
+	probe_array[eID].callbacks[0] = ltt_serialize_data;
+	result = marker_set_probe(probe_array[eID].name,
+			probe_array[eID].format,
+			ltt_trace, &probe_array[eID]);
+	if (!result)
+		printk(KERN_INFO "LTT unable to register probe %s\n",
+			probe_array[eID].name);
+ 	ltt_write_full_tsc();
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		if (eID == 1)
+			continue;
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-core.c b/ltt/probes/ltt-probe-core.c
new file mode 100644
index 0000000..f07f8ff
--- /dev/null
+++ b/ltt/probes/ltt-probe-core.c
@@ -0,0 +1,109 @@
+/*
+ * ltt-probe-core.c
+ *
+ * Core probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "core"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "core_facility_load", "%s %4b %4b %4b %4b %4b %4b %4b",
+		GET_CHANNEL_INDEX(facilities) },
+	{ "core_facility_unload", "%4b",
+		GET_CHANNEL_INDEX(facilities) },
+	{ "core_time_heartbeat", MARK_NOARGS },
+	{ "core_time_heartbeat_full", "%8b" },
+	{ "core_state_dump_facility_load", "%s %4b %4b %4b %4b %4b %4b %4b",
+		GET_CHANNEL_INDEX(facilities) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-fs.c b/ltt/probes/ltt-probe-fs.c
new file mode 100644
index 0000000..1b070b7
--- /dev/null
+++ b/ltt/probes/ltt-probe-fs.c
@@ -0,0 +1,177 @@
+/*
+ * ltt-probe-fs.c
+ *
+ * FS probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+#include <asm/uaccess.h>
+
+/* Expects va args : (int elem_num, const char __user *s)
+ * Element size is implicit (sizeof(char)). */
+static char *ltt_serialize_fs_data(char *buffer, char *str,
+	struct ltt_serialize_closure *closure,
+	int align, const char *fmt, va_list *args)
+{
+	int elem_size;
+	int elem_num;
+	const char __user  *s;
+	unsigned long noncopy;
+
+	elem_num = va_arg(*args, int);
+	s = va_arg(*args, const char __user *);
+	elem_size = sizeof(*s);
+
+	if (align)
+		str += ltt_align((long)str, sizeof(int));
+	if (buffer)
+		*(int*)str = elem_num;
+	str += sizeof(int);
+
+	if (elem_num > 0) {
+		/* No alignment required for char */
+		if (buffer) {
+			noncopy = __copy_from_user_inatomic(str, s,
+					elem_num*elem_size);
+			memset(str+(elem_num*elem_size)-noncopy, 0, noncopy);
+		}
+		str += (elem_num*elem_size);
+	}
+	/* Following alignment for genevent
+	 * compatibility */
+	if (align)
+		str += ltt_align((long)str, sizeof(void*));
+	return str;
+}
+
+#define FACILITY_NAME "fs"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "fs_buffer_wait_start", "%p", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_buffer_wait_end", "%p", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_exec", "%s", GET_CHANNEL_INDEX(processes),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_open", "%d %s", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_close", "%u", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_read", "%u %zu", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_pread64", "%u %zu %8b", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_readv", "%lu %lu", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_write", "%u %zu", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_pwrite64", "%u %zu %8b", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_writev", "%lu %lu", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_lseek", "%u %8b %u", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_llseek", "%u %8b %u", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_ioctl", "%u %u %lu", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_select", "%d %8b", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_pollfd", "%d", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data },
+	{ "fs_read_data", "%u %zd %k", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data,
+		.callbacks[1] = ltt_serialize_fs_data},
+	{ "fs_write_data", "%u %zd %k", GET_CHANNEL_INDEX(cpu),
+		.callbacks[0] = ltt_serialize_data,
+		.callbacks[1] = ltt_serialize_fs_data },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		//probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel.c b/ltt/probes/ltt-probe-kernel.c
new file mode 100644
index 0000000..3466288
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel.c
@@ -0,0 +1,164 @@
+/*
+ * ltt-probe-kernel.c
+ *
+ * kernel probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_process_fork", "%d %d %d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_process_exit", "%d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_process_free", "%d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_process_wait", "%d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_process_signal", "%d %d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_sched_wait_task", "%d %ld", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_sched_try_wakeup", "%d %ld", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_sched_wakeup_new_task", "%d %ld",
+		GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_sched_migrate_task", "%d %ld %d",
+		GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_sched_schedule", "%d %d %ld", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_printk", "%p", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "kernel_vprintk", "%c %*:*v %p", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "kernel_timer_itimer_expired", "%d", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_timer_itimer_set", "%d %*.*r %*.*r",
+		GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_timer_set", "%lu %p %lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_timer_update_time", "%8b %*.*r %*.*r",
+		GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_timer_timeout", "%d", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_softirq_entry", "%lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_softirq_exit", "%lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_tasklet_low_entry", "%p %lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_tasklet_low_exit", "%p %lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_tasklet_high_entry", "%p %lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_tasklet_high_exit", "%p %lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_kthread_stop", "%d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_kthread_stop_ret", "%d", GET_CHANNEL_INDEX(processes),
+		_MF_DEFAULT },
+	{ "kernel_module_load", "%s", GET_CHANNEL_INDEX(modules),
+		_MF_DEFAULT },
+	{ "kernel_module_free", "%s", GET_CHANNEL_INDEX(modules),
+		_MF_DEFAULT },
+	{ "kernel_irq_entry", "%u %u", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+	{ "kernel_irq_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = _marker_set_probe(probe_array[eID].flags,
+				probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel_arch_arm.c b/ltt/probes/ltt-probe-kernel_arch_arm.c
new file mode 100644
index 0000000..137f32c
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel_arch_arm.c
@@ -0,0 +1,108 @@
+/*
+ * ltt-probe-kernel_arch_arm.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_arch_trap_entry", "%ld %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_trap_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_ipc_call", "%u %d", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_kthread_create", "%ld %p",
+		GET_CHANNEL_INDEX(processes) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel_arch_i386.c b/ltt/probes/ltt-probe-kernel_arch_i386.c
new file mode 100644
index 0000000..71fbd4e
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel_arch_i386.c
@@ -0,0 +1,108 @@
+/*
+ * ltt-probe-kernel_arch_i386.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_arch_trap_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_trap_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_ipc_call", "%u %d", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_kthread_create", "%ld %p",
+		GET_CHANNEL_INDEX(processes) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel_arch_mips.c b/ltt/probes/ltt-probe-kernel_arch_mips.c
new file mode 100644
index 0000000..156e422
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel_arch_mips.c
@@ -0,0 +1,108 @@
+/*
+ * ltt-probe-kernel_arch_mips.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_arch_trap_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_trap_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_ipc_call", "%u %d", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_kthread_create", "%ld %p",
+		GET_CHANNEL_INDEX(processes) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel_arch_powerpc.c b/ltt/probes/ltt-probe-kernel_arch_powerpc.c
new file mode 100644
index 0000000..97850f0
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel_arch_powerpc.c
@@ -0,0 +1,108 @@
+/*
+ * ltt-probe-kernel_arch_powerpc.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_arch_trap_entry", "%ld %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_trap_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_ipc_call", "%u %d", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_kthread_create", "%ld %p",
+		GET_CHANNEL_INDEX(processes) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel_arch_ppc.c b/ltt/probes/ltt-probe-kernel_arch_ppc.c
new file mode 100644
index 0000000..f792ef3
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel_arch_ppc.c
@@ -0,0 +1,108 @@
+/*
+ * ltt-probe-kernel_arch_ppc.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_arch_trap_entry", "%ld %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_trap_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_ipc_call", "%u %d", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_kthread_create", "%ld %p",
+		GET_CHANNEL_INDEX(processes) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-kernel_arch_x86_64.c b/ltt/probes/ltt-probe-kernel_arch_x86_64.c
new file mode 100644
index 0000000..8376034
--- /dev/null
+++ b/ltt/probes/ltt-probe-kernel_arch_x86_64.c
@@ -0,0 +1,108 @@
+/*
+ * ltt-probe-kernel_arch_x86_64.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "kernel_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "kernel_arch_trap_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_trap_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_entry", "%d %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_syscall_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_ipc_call", "%u %d", GET_CHANNEL_INDEX(cpu) },
+	{ "kernel_arch_kthread_create", "%ld %p",
+		GET_CHANNEL_INDEX(processes) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-list.c b/ltt/probes/ltt-probe-list.c
new file mode 100644
index 0000000..e8a06c1
--- /dev/null
+++ b/ltt/probes/ltt-probe-list.c
@@ -0,0 +1,109 @@
+/*
+ * ltt-probe-list.c
+ *
+ * list probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "list"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "list_module", "%s %d %lu", GET_CHANNEL_INDEX(modules) },
+	{ "list_file_descriptor", "%s %d %u", GET_CHANNEL_INDEX(cpu) },
+	{ "list_vm_map", "%d %lu %lu %lu %lu %lu", GET_CHANNEL_INDEX(cpu) },
+	{ "list_interrupt", "%s %s %u", GET_CHANNEL_INDEX(interrupts) },
+	{ "list_process_state", "%d %d %s %d %d %d %d %d",
+		GET_CHANNEL_INDEX(processes) },
+	{ "list_network_ip_interface", "%s %4b %d",
+		GET_CHANNEL_INDEX(network) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-locking.c b/ltt/probes/ltt-probe-locking.c
new file mode 100644
index 0000000..3e28955
--- /dev/null
+++ b/ltt/probes/ltt-probe-locking.c
@@ -0,0 +1,114 @@
+/*
+ * ltt-probe-locking.c
+ *
+ * locking probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "locking"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "locking_hardirqs_on", "%lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "locking_hardirqs_off", "%lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "locking_softirqs_on", "%lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "locking_softirqs_off", "%lu", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "locking_lock_acquire", "%lu %u %p %d", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+	{ "locking_lock_release", "%lu %p %d", GET_CHANNEL_INDEX(cpu),
+		_MF_DEFAULT & ~_MF_LOCKDEP },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = _marker_set_probe(probe_array[eID].flags,
+				probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-mm.c b/ltt/probes/ltt-probe-mm.c
new file mode 100644
index 0000000..a0376be
--- /dev/null
+++ b/ltt/probes/ltt-probe-mm.c
@@ -0,0 +1,109 @@
+/*
+ * ltt-probe-mm.c
+ *
+ * mm probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "mm"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "mm_handle_fault_entry", "%lu %ld", GET_CHANNEL_INDEX(cpu) },
+	{ "mm_handle_fault_exit", MARK_NOARGS, GET_CHANNEL_INDEX(cpu) },
+	{ "mm_filemap_wait_start", "%p", GET_CHANNEL_INDEX(cpu) },
+	{ "mm_filemap_wait_end", "%p", GET_CHANNEL_INDEX(cpu) },
+	{ "mm_page_alloc", "%u %p", GET_CHANNEL_INDEX(cpu) },
+	{ "mm_page_free", "%u %p", GET_CHANNEL_INDEX(cpu) },
+	{ "mm_swap_in", "%lu", GET_CHANNEL_INDEX(cpu) },
+	{ "mm_swap_out", "%p", GET_CHANNEL_INDEX(cpu) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-net.c b/ltt/probes/ltt-probe-net.c
new file mode 100644
index 0000000..e093055
--- /dev/null
+++ b/ltt/probes/ltt-probe-net.c
@@ -0,0 +1,109 @@
+/*
+ * ltt-probe-net.c
+ *
+ * Network probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+
+#define FACILITY_NAME "net"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "net_socket_sendmsg", "%p %d %d %d %zu", GET_CHANNEL_INDEX(cpu) },
+	{ "net_socket_recvmsg", "%p %d %d %d %zu", GET_CHANNEL_INDEX(cpu) },
+	{ "net_socket_create", "%p %d %d %d %d", GET_CHANNEL_INDEX(cpu) },
+	{ "net_socket_call", "%d %lu", GET_CHANNEL_INDEX(cpu) },
+	{ "net_dev_xmit", "%p %2b", GET_CHANNEL_INDEX(cpu) },
+	{ "net_dev_receive", "%p %2b", GET_CHANNEL_INDEX(cpu) },
+	{ "net_insert_ifa", "%s %4b", GET_CHANNEL_INDEX(network) },
+	{ "net_del_ifa", "%s", GET_CHANNEL_INDEX(network) },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-stack_arch_i386.c b/ltt/probes/ltt-probe-stack_arch_i386.c
new file mode 100644
index 0000000..f650b95
--- /dev/null
+++ b/ltt/probes/ltt-probe-stack_arch_i386.c
@@ -0,0 +1,412 @@
+/*
+ * ltt-probe-stack_arch_i386.c
+ *
+ * stack arch i386 probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ptrace.h>
+#include <linux/ltt-tracer.h>
+
+struct stack_dump_args {
+	unsigned long ebp;
+};
+
+/* Kernel specific trace stack dump routines, from arch/i386/kernel/traps.c */
+
+/* Event kernel_dump structures 
+ * ONLY USE IT ON THE CURRENT STACK.
+ * It does not protect against other stack modifications and _will_
+ * cause corruption upon race between threads.
+ *
+ * FIXME : using __kernel_text_address here can break things if a module is
+ * loaded during tracing. The real function pointers are OK : if they are on our
+ * stack, it means that the module refcount must not be 0, but the problem comes
+ * from the "false positives" : that that appears to be a function pointer.
+ * The solution to this problem : 
+ * Without frame pointers, we have one version with spinlock irqsave (never call
+ * this in NMI context, and another with a trylock, which can fail. */
+
+static inline int dump_valid_stack_ptr(struct thread_info *tinfo, void *p)
+{
+	return	p > (void *)tinfo &&
+		p < (void *)tinfo + THREAD_SIZE - 3;
+}
+
+/* norm : inline */
+static noinline unsigned long dump_context_stack(struct thread_info *tinfo,
+		unsigned long *stack, unsigned long ebp,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	unsigned long addr;
+
+#ifdef	CONFIG_FRAME_POINTER
+	while (dump_valid_stack_ptr(tinfo, (void *)ebp)) {
+		unsigned long new_ebp;
+		if (buffer != NULL) {
+			unsigned long *dest = (unsigned long*)*str;
+			addr = *(unsigned long *)(ebp + 4);
+			*dest = addr;
+		} else {
+			(*len)++;
+		}
+		(*str) += sizeof(unsigned long);
+		new_ebp = *(unsigned long *)ebp;
+		if (new_ebp <= ebp)
+			break;
+		ebp = new_ebp;
+	}
+#else
+	while (dump_valid_stack_ptr(tinfo, stack)) {
+		addr = *stack++;
+		if (__kernel_text_address(addr)) {
+			if (buffer != NULL) {
+				unsigned long *dest = (unsigned long*)*str;
+				*dest = addr;
+			} else {
+				(*len)++;
+			}
+			(*str) += sizeof(unsigned long);
+		}
+	}
+#endif
+	return ebp;
+}
+
+static noinline void dump_trace(unsigned long * stack,
+		unsigned long ebp,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	while (1) {
+		struct thread_info *context;
+		context = (struct thread_info *)
+			((unsigned long)stack & (~(THREAD_SIZE - 1)));
+		ebp = dump_context_stack(context, stack, ebp,
+				buffer, str, len);
+		stack = (unsigned long*)context->previous_esp;
+		if (!stack)
+			break;
+	}
+}
+
+static noinline char *ltt_serialize_kernel_stack(char *buffer, char *str,
+	struct ltt_serialize_closure *closure,
+	int align, const char *fmt, va_list *args)
+{
+	struct stack_dump_args *stargs;
+
+	/* Ugly and crude argument passing hack part 2. */
+	stargs = (struct stack_dump_args *)fmt;
+
+	if (align)
+		str += ltt_align((long)str,
+			max(sizeof(int), sizeof(unsigned long)));
+	if (buffer)
+		*(int*)str = (int)closure->cb_args[0];
+	str += sizeof(int);
+
+	if (!buffer)
+		closure->cb_args[0] = 0;
+
+	if (align)
+		str += ltt_align((long)str, sizeof(unsigned long));
+	dump_trace((unsigned long*)stargs, stargs->ebp, buffer, &str,
+			&closure->cb_args[0]);
+
+	/* Following alignment for genevent
+	 * compatibility */
+	if (align)
+		str += ltt_align((long)str, sizeof(void*));
+	return str;
+}
+
+/* Expects va args : (struct pt_regs *regs) */
+static void ltt_trace_kernel_stack(const struct __mark_marker_data *mdata,
+	const char *fmt, ...)
+{
+	struct stack_dump_args stargs;
+	va_list args;
+	struct pt_regs *regs;
+
+#ifndef CONFIG_LTT_KERNEL_STACK
+	return;
+#endif
+
+	va_start(args, fmt);
+	regs = va_arg(args, struct pt_regs *);
+	if (unlikely(!regs || user_mode_vm(regs)))
+		goto end;
+	/* Grab ebp right from our regs */
+	asm ("movl %%ebp, %0" : "=r" (stargs.ebp) : );
+	/* Ugly and crude argument passing hack part 1. */
+	ltt_vtrace(mdata, (const char*)&stargs, args);
+end:
+	va_end(args);
+}
+
+/* FIXME : how could we autodetect this.... ?!? disabled for now. */
+static noinline void dump_fp_process_stack(
+		struct pt_regs *regs,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	uint32_t addr;
+	uint32_t next_ebp;
+	uint32_t *iter;
+	uint32_t *dest = (uint32_t*)*str;
+
+	if (buffer)
+		*dest = regs->eip;
+	else
+		(*len)++;
+	dest++;
+
+	/* Start at the topmost ebp */
+	iter = (uint32_t*)regs->ebp;
+
+	/* Keep on going until we reach the end of the process' stack limit or
+	 * find an invalid ebp. */
+	while (!get_user(next_ebp, iter)) {
+		/* If another thread corrupts the thread user space stack
+		 * concurrently */
+		if (buffer)
+			if (dest == (uint32_t*)(*str) + *len)
+				break;
+		if (next_ebp <= (uint32_t)(iter+1))
+			break;
+		if (buffer)
+			*dest = addr;
+		else
+			(*len)++;
+		dest++;
+		iter = (uint32_t*)next_ebp;
+	}
+
+	/* Concurrently been changed : pad with zero */
+	if (buffer)
+		while (dest < (uint32_t*)(*str) + *len) {
+			*dest = 0;
+			dest++;
+		}
+	*str = (char*)dest;
+}
+
+static noinline void dump_nofp_process_stack(
+		struct pt_regs *regs,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	uint32_t addr;
+	uint32_t *iter;
+	uint32_t *dest = (uint32_t*)*str;
+	uint32_t *prev_iter, *beg_iter;
+
+	if (buffer)
+		*dest = regs->eip;
+	else
+		(*len)++;
+	dest++;
+
+	/* FIXME : currently detects code addresses from executable only,
+	 * not libraries */
+	/* Start at the top of the user stack */
+	prev_iter = beg_iter = iter = (uint32_t*) regs->esp;
+
+	while (!get_user(addr, iter)) {
+		if (buffer)
+			if (dest == (uint32_t*)(*str) + *len)
+				break;
+		/* Does this LOOK LIKE an address in the program */
+		if (addr > current->mm->start_code &&
+			addr < current->mm->end_code) {
+			if (buffer)
+				*dest = addr;
+			else
+				(*len)++;
+			dest++;
+		}
+		prev_iter = iter;
+		iter++;
+		if (iter >
+			prev_iter + CONFIG_LTT_PROCESS_MAX_FUNCTION_STACK)
+			break;
+		if (iter > beg_iter + CONFIG_LTT_PROCESS_MAX_STACK_LEN)
+			break;
+	}
+
+	/* Concurrently been changed : pad with zero */
+	if (buffer)
+		while (dest < (uint32_t*)(*str) + *len) {
+			*dest = 0;
+			dest++;
+		}
+	*str = (char*)dest;
+}
+
+static noinline char *ltt_serialize_process_stack(char *buffer, char *str,
+	struct ltt_serialize_closure *closure,
+	int align, const char *fmt, va_list *args)
+{
+	struct pt_regs *regs;
+
+	/* Ugly and crude argument passing hack part 2 (revisited). */
+	regs = (struct pt_regs *)fmt;
+
+	if (align)
+		str += ltt_align((long)str,
+			max(sizeof(int), sizeof(unsigned long)));
+	if (buffer)
+		*(int*)str = (int)closure->cb_args[0];
+	str += sizeof(int);
+
+	if (!buffer)
+		closure->cb_args[0] = 0;
+
+	if (align)
+		str += ltt_align((long)str, sizeof(unsigned long));
+	dump_nofp_process_stack(regs, buffer, &str, &closure->cb_args[0]);
+
+	/* Following alignment for genevent
+	 * compatibility */
+	if (align)
+		str += ltt_align((long)str, sizeof(void*));
+	return str;
+}
+
+/* Expects va args : (struct pt_regs *regs) */
+static void ltt_trace_process_stack(const struct __mark_marker_data *mdata,
+	const char *fmt, ...)
+{
+	va_list args;
+	struct pt_regs *regs;
+
+#ifndef CONFIG_LTT_PROCESS_STACK
+	return;
+#endif
+
+	va_start(args, fmt);
+	regs = va_arg(args, struct pt_regs *);
+	if (unlikely(!regs || !user_mode_vm(regs)))
+		goto end;
+	/* Ugly and crude argument passing hack part 1 (revisited). */
+	ltt_vtrace(mdata, (const char*)regs, args);
+end:
+	va_end(args);
+}
+
+#define FACILITY_NAME "stack_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "stack_arch_irq_dump_kernel_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_kernel_stack,
+		.callbacks[0] = ltt_serialize_kernel_stack },
+	{ "stack_arch_nmi_dump_kernel_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_kernel_stack,
+		.callbacks[0] = ltt_serialize_kernel_stack },
+	{ "stack_arch_syscall_dump_kernel_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_kernel_stack,
+		.callbacks[0] = ltt_serialize_kernel_stack },
+	{ "stack_arch_irq_dump_process32_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_process_stack,
+		.callbacks[0] = ltt_serialize_process_stack },
+	{ "stack_arch_syscall_dump_process32_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_process_stack,
+		.callbacks[0] = ltt_serialize_process_stack },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				probe_array[eID].probe_func, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-stack_arch_x86_64.c b/ltt/probes/ltt-probe-stack_arch_x86_64.c
new file mode 100644
index 0000000..fa3264e
--- /dev/null
+++ b/ltt/probes/ltt-probe-stack_arch_x86_64.c
@@ -0,0 +1,686 @@
+/*
+ * ltt-probe-stack_arch_x86_64.c
+ *
+ * stack arch x86_64 probe
+ *
+ * Part of LTTng
+ *
+ * Mathieu Desnoyers, March 2007
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ptrace.h>
+#include <linux/ltt-tracer.h>
+
+#include <asm/desc_defs.h>
+#include <asm/user32.h>
+
+/* Kernel specific trace stack dump routines, from arch/x86_64/kernel/traps.c */
+
+/* Event kernel_dump structures 
+ * ONLY USE IT ON THE CURRENT STACK.
+ * It does not protect against other stack modifications and _will_
+ * cause corruption upon race between threads.
+ * FIXME : using __kernel_text_address here can break things if a module is
+ * loaded during tracing. The real function pointers are OK : if they are on our
+ * stack, it means that the module refcount must not be 0, but the problem comes
+ * from the "false positives" : that that appears to be a function pointer.
+ * The solution to this problem : 
+ * Without frame pointers, we have one version with spinlock irqsave (never call
+ * this in NMI context, and another with a trylock, which can fail. */
+
+/* From traps.c */
+
+static noinline unsigned long *trace_in_exception_stack(unsigned cpu,
+					unsigned long stack,
+					unsigned *usedp, const char **idp)
+{
+	static char ids[][8] = {
+		[DEBUG_STACK - 1] = "#DB",
+		[NMI_STACK - 1] = "NMI",
+		[DOUBLEFAULT_STACK - 1] = "#DF",
+		[STACKFAULT_STACK - 1] = "#SS",
+		[MCE_STACK - 1] = "#MC",
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+		[N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+#endif
+	};
+	unsigned k;
+
+	/*
+	 * Iterate over all exception stacks, and figure out whether
+	 * 'stack' is in one of them:
+	 */
+	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+		unsigned long end = per_cpu(orig_ist, cpu).ist[k];
+		/*
+		 * Is 'stack' above this exception frame's end?
+		 * If yes then skip to the next frame.
+		 */
+		if (stack >= end)
+			continue;
+		/*
+		 * Is 'stack' above this exception frame's start address?
+		 * If yes then we found the right frame.
+		 */
+		if (stack >= end - EXCEPTION_STKSZ) {
+			/*
+			 * Make sure we only iterate through an exception
+			 * stack once. If it comes up for the second time
+			 * then there's something wrong going on - just
+			 * break out and return NULL:
+			 */
+			if (*usedp & (1U << k))
+				break;
+			*usedp |= 1U << k;
+			*idp = ids[k];
+			return (unsigned long *)end;
+		}
+		/*
+		 * If this is a debug stack, and if it has a larger size than
+		 * the usual exception stacks, then 'stack' might still
+		 * be within the lower portion of the debug stack:
+		 */
+#if DEBUG_STKSZ > EXCEPTION_STKSZ
+		if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) {
+			unsigned j = N_EXCEPTION_STACKS - 1;
+
+			/*
+			 * Black magic. A large debug stack is composed of
+			 * multiple exception stack entries, which we
+			 * iterate through now. Dont look:
+			 */
+			do {
+				++j;
+				end -= EXCEPTION_STKSZ;
+				ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+			} while (stack < end - EXCEPTION_STKSZ);
+			if (*usedp & (1U << j))
+				break;
+			*usedp |= 1U << j;
+			*idp = ids[j];
+			return (unsigned long *)end;
+		}
+#endif
+	}
+	return NULL;
+}
+
+/*
+ * x86-64 can have upto three kernel stacks: 
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+{
+	void *t = (void *)tinfo;
+        return p > t && p < t + THREAD_SIZE - 3;
+}
+
+/* Must be called with preemption disabled */
+static noinline void dump_trace(unsigned long *stack,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	const unsigned cpu = smp_processor_id();
+	unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
+	unsigned used = 0;
+	struct thread_info *tinfo;
+
+#define HANDLE_STACK(cond) \
+	do while (cond) { \
+		unsigned long addr = *stack++; \
+		if (__kernel_text_address(addr)) { \
+			/* \
+			 * If the address is either in the text segment of the \
+			 * kernel, or in the region which contains vmalloc'ed \
+			 * memory, it *may* be the address of a calling \
+			 * routine; if so, print it so that someone tracing \
+			 * down the cause of the crash will be able to figure \
+			 * out the call path that was taken. \
+			 */ \
+			if (buffer != NULL) { \
+				unsigned long *dest = (unsigned long*)*str; \
+				*dest = addr; \
+			} else { \
+				(*len)++; \
+			} \
+			(*str) += sizeof(unsigned long); \
+		} \
+	} while (0)
+
+	/*
+	 * Print function call entries in all stacks, starting at the
+	 * current stack address. If the stacks consist of nested
+	 * exceptions
+	 */
+	for (;;) {
+		const char *id;
+		unsigned long *estack_end;
+		estack_end = trace_in_exception_stack(cpu, (unsigned long)stack,
+						&used, &id);
+
+		if (estack_end) {
+			HANDLE_STACK (stack < estack_end);
+			/*
+			 * We link to the next stack via the
+			 * second-to-last pointer (index -2 to end) in the
+			 * exception stack:
+			 */
+			stack = (unsigned long *) estack_end[-2];
+			continue;
+		}
+		if (irqstack_end) {
+			unsigned long *irqstack;
+			irqstack = irqstack_end -
+				(IRQSTACKSIZE - 64) / sizeof(*irqstack);
+
+			if (stack >= irqstack && stack < irqstack_end) {
+				HANDLE_STACK (stack < irqstack_end);
+				/*
+				 * We link to the next stack (which would be
+				 * the process stack normally) the last
+				 * pointer (index -1 to end) in the IRQ stack:
+				 */
+				stack = (unsigned long *) (irqstack_end[-1]);
+				irqstack_end = NULL;
+				continue;
+			}
+		}
+		break;
+	}
+
+	/*
+	 * This handles the process stack:
+	 */
+	tinfo = current_thread_info();
+	HANDLE_STACK (valid_stack_ptr(tinfo, stack));
+#undef HANDLE_STACK
+}
+
+
+static noinline char *ltt_serialize_kernel_stack(char *buffer, char *str,
+	struct ltt_serialize_closure *closure,
+	int align, const char *fmt, va_list *args)
+{
+	/* Ugly and crude argument passing hack part 2. */
+	unsigned long *stack = (unsigned long*)fmt;
+
+	if (align)
+		str += ltt_align((long)str,
+			max(sizeof(int), sizeof(unsigned long)));
+	if (buffer)
+		*(int*)str = (int)closure->cb_args[0];
+	str += sizeof(int);
+
+	if (!buffer)
+		closure->cb_args[0] = 0;
+
+	if (align)
+		str += ltt_align((long)str, sizeof(unsigned long));
+	dump_trace(stack, buffer, &str, &closure->cb_args[0]);
+
+	/* Following alignment for genevent
+	 * compatibility */
+	if (align)
+		str += ltt_align((long)str, sizeof(void*));
+	return str;
+}
+
+/* Expects va args : (struct pt_regs *regs) */
+static void ltt_trace_kernel_stack(const struct __mark_marker_data *mdata,
+	const char *fmt, ...)
+{
+	struct pt_regs *regs;
+	va_list args;
+
+#ifndef CONFIG_LTT_KERNEL_STACK
+	return;
+#endif
+
+	va_start(args, fmt);
+	regs = va_arg(args, struct pt_regs *);
+	if (unlikely(!regs || user_mode_vm(regs)))
+		goto end;
+	/* Ugly and crude argument passing hack part 1. */
+	ltt_vtrace(mdata, (const char*)&regs, args);
+end:
+	va_end(args);
+}
+
+/* FIXME : how could we autodetect this.... ?!? disabled for now. */
+static noinline void dump_fp_process32_stack(
+		struct pt_regs *real_regs,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	uint32_t addr;
+	uint32_t next_ebp;
+	uint32_t *iter;
+	uint32_t *dest = (uint32_t*)*str;
+	struct user_regs_struct32 *regs;
+	
+	regs = (struct user_regs_struct32 *)real_regs;
+
+	if (buffer)
+		*dest = PTR_LOW(regs->eip);
+	else
+		(*len)++;
+	dest++;
+
+	/* Start at the topmost ebp */
+	iter = (uint32_t*)PTR_LOW(regs->ebp);
+
+	/* Keep on going until we reach the end of the process' stack limit or
+	 * find an invalid ebp. */
+	while (!get_user(next_ebp, iter)) {
+		/* If another thread corrupts the thread user space stack
+		 * concurrently */
+		if (buffer)
+			if (dest == (uint32_t*)(*str) + *len)
+				break;
+		if (PTR_LOW(next_ebp) <= (unsigned long)(iter+1))
+			break;
+		if (buffer)
+			*dest = addr;
+		else
+			(*len)++;
+		dest++;
+		iter = (uint32_t*)PTR_LOW(next_ebp);
+	}
+
+	/* Concurrently been changed : pad with zero */
+	if (buffer)
+		while (dest < (uint32_t*)(*str) + *len) {
+			*dest = 0;
+			dest++;
+		}
+	*str = (char*)dest;
+}
+
+static noinline void dump_nofp_process32_stack(
+		struct pt_regs *real_regs,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	uint32_t addr;
+	uint32_t *iter;
+	uint32_t *dest = (uint32_t*)*str;
+	uint32_t *prev_iter, *beg_iter;
+	struct user_regs_struct32 *regs;
+
+	regs = (struct user_regs_struct32 *)real_regs;
+
+	if (buffer)
+		*dest = PTR_LOW(regs->eip);
+	else
+		(*len)++;
+	dest++;
+
+	/* FIXME : currently detects code addresses from executable only,
+	 * not libraries */
+	/* Start at the top of the user stack */
+	prev_iter = beg_iter = iter = (uint32_t*)PTR_LOW(regs->esp);
+
+	while (!get_user(addr, iter)) {
+		if (buffer)
+			if (dest == (uint32_t*)(*str) + *len)
+				break;
+		/* Does this LOOK LIKE an address in the program */
+		if (addr > current->mm->start_code &&
+			addr < current->mm->end_code) {
+			if (buffer)
+				*dest = addr;
+			else
+				(*len)++;
+			dest++;
+		}
+		prev_iter = iter;
+		iter++;
+		if (iter >
+			prev_iter + CONFIG_LTT_PROCESS_MAX_FUNCTION_STACK)
+			break;
+		if (iter > beg_iter + CONFIG_LTT_PROCESS_MAX_STACK_LEN)
+			break;
+	}
+
+	/* Concurrently been changed : pad with zero */
+	if (buffer)
+		while (dest < (uint32_t*)(*str) + *len) {
+			*dest = 0;
+			dest++;
+		}
+	*str = (char*)dest;
+}
+
+static noinline void dump_fp_process64_stack(
+		struct pt_regs *regs,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	uint64_t addr;
+	uint64_t next_rbp;
+	uint64_t *iter;
+	uint64_t *dest = (uint64_t*)*str;
+
+	if (buffer)
+		*dest = regs->rip;
+	else
+		(*len)++;
+	dest++;
+
+	/* Start at the topmost rbp */
+	iter = (uint64_t*)regs->rbp;
+
+	/* Keep on going until we reach the end of the process' stack limit or
+	 * find an invalid ebp. */
+	while (!get_user(next_rbp, iter)) {
+		/* If another thread corrupts the thread user space stack
+		 * concurrently */
+		if (buffer)
+			if (dest == (uint64_t*)(*str) + *len)
+				break;
+		if (next_rbp <= (uint64_t)(iter+1))
+			break;
+		if (buffer)
+			*dest = addr;
+		else
+			(*len)++;
+		dest++;
+		iter = (uint64_t*)next_rbp;
+	}
+
+	/* Concurrently been changed : pad with zero */
+	if (buffer)
+		while (dest < (uint64_t*)(*str) + *len) {
+			*dest = 0;
+			dest++;
+		}
+	*str = (char*)dest;
+}
+
+static noinline void dump_nofp_process64_stack(
+		struct pt_regs *regs,
+		char *buffer,
+		char **str,
+		long *len)
+{
+	uint64_t addr;
+	uint64_t *iter;
+	uint64_t *dest = (uint64_t*)*str;
+	uint64_t *prev_iter, *beg_iter;
+
+	if (buffer)
+		*dest = regs->rip;
+	else
+		(*len)++;
+	dest++;
+
+	/* FIXME : currently detects code addresses from executable only,
+	 * not libraries */
+	/* Start at the top of the user stack */
+	prev_iter = beg_iter = iter = (uint64_t*) regs->rsp;
+
+	while (!get_user(addr, iter)) {
+		if (buffer)
+			if (dest == (uint64_t*)(*str) + *len)
+				break;
+		/* Does this LOOK LIKE an address in the program */
+		if (addr > current->mm->start_code &&
+			addr < current->mm->end_code) {
+			if (buffer)
+				*dest = addr;
+			else
+				(*len)++;
+			dest++;
+		}
+		prev_iter = iter;
+		iter++;
+		if (iter >
+			prev_iter + CONFIG_LTT_PROCESS_MAX_FUNCTION_STACK)
+			break;
+		if (iter > beg_iter + CONFIG_LTT_PROCESS_MAX_STACK_LEN)
+			break;
+	}
+
+	/* Concurrently been changed : pad with zero */
+	if (buffer)
+		while (dest < (uint64_t*)(*str) + *len) {
+			*dest = 0;
+			dest++;
+		}
+	*str = (char*)dest;
+}
+
+static noinline char *ltt_serialize_process32_stack(char *buffer, char *str,
+	struct ltt_serialize_closure *closure,
+	int align, const char *fmt, va_list *args)
+{
+	struct pt_regs *regs;
+
+	/* Ugly and crude argument passing hack part 2 (revisited). */
+	regs = (struct pt_regs *)fmt;
+
+	if (align)
+		str += ltt_align((long)str,
+			max(sizeof(int), sizeof(uint32_t)));
+
+	if (buffer)
+		*(int*)str = (int)closure->cb_args[0];
+	str += sizeof(int);
+
+	if (!buffer)
+		closure->cb_args[0] = 0;
+
+	if (align)
+		str += ltt_align((long)str, sizeof(uint32_t));
+	dump_nofp_process32_stack(regs, buffer, &str,
+		&closure->cb_args[0]);
+
+	/* Following alignment for genevent
+	 * compatibility */
+	if (align)
+		str += ltt_align((long)str, sizeof(void*));
+	return str;
+}
+
+static noinline char *ltt_serialize_process64_stack(char *buffer, char *str,
+	struct ltt_serialize_closure *closure,
+	int align, const char *fmt, va_list *args)
+{
+	struct pt_regs *regs;
+
+	/* Ugly and crude argument passing hack part 2 (revisited). */
+	regs = (struct pt_regs *)fmt;
+
+	if (align)
+		str += ltt_align((long)str,
+			max(sizeof(int), sizeof(uint64_t)));
+
+	if (buffer)
+		*(int*)str = (int)closure->cb_args[0];
+	str += sizeof(int);
+
+	if (!buffer)
+		closure->cb_args[0] = 0;
+
+	if (align)
+		str += ltt_align((long)str, sizeof(uint64_t));
+	dump_nofp_process64_stack(regs, buffer, &str,
+		&closure->cb_args[0]);
+
+	/* Following alignment for genevent
+	 * compatibility */
+	if (align)
+		str += ltt_align((long)str, sizeof(void*));
+	return str;
+}
+
+
+/* Expects va args : (struct pt_regs *regs) */
+static void ltt_trace_process32_stack(const struct __mark_marker_data *mdata,
+	const char *fmt, ...)
+{
+	va_list args;
+	struct pt_regs *regs;
+
+#ifndef CONFIG_LTT_PROCESS_STACK
+	return;
+#endif
+
+	if (!test_thread_flag(TIF_IA32))
+		return;
+
+	va_start(args, fmt);
+	regs = va_arg(args, struct pt_regs *);
+	if (unlikely(!regs || !user_mode_vm(regs)))
+		goto end;
+	/* Ugly and crude argument passing hack part 1 (revisited). */
+	ltt_vtrace(mdata, (const char*)regs, args);
+end:
+	va_end(args);
+}
+
+/* Expects va args : (struct pt_regs *regs) */
+static void ltt_trace_process64_stack(const struct __mark_marker_data *mdata,
+	const char *fmt, ...)
+{
+	va_list args;
+	struct pt_regs *regs;
+
+#ifndef CONFIG_LTT_PROCESS_STACK
+	return;
+#endif
+
+	if (test_thread_flag(TIF_IA32))
+		return;
+
+	va_start(args, fmt);
+	regs = va_arg(args, struct pt_regs *);
+	if (unlikely(!regs || !user_mode_vm(regs)))
+		goto end;
+	/* Ugly and crude argument passing hack part 1 (revisited). */
+	ltt_vtrace(mdata, (const char*)regs, args);
+end:
+	va_end(args);
+}
+#define FACILITY_NAME "stack_arch"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "stack_arch_irq_dump_kernel_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_kernel_stack,
+		.callbacks[0] = ltt_serialize_kernel_stack },
+	{ "stack_arch_nmi_dump_kernel_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_kernel_stack,
+		.callbacks[0] = ltt_serialize_kernel_stack },
+	{ "stack_arch_syscall_dump_kernel_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_kernel_stack,
+		.callbacks[0] = ltt_serialize_kernel_stack },
+	{ "stack_arch_irq_dump_process32_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_process32_stack,
+		.callbacks[0] = ltt_serialize_process32_stack },
+	{ "stack_arch_syscall_dump_process32_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_process32_stack,
+		.callbacks[0] = ltt_serialize_process32_stack },
+	{ "stack_arch_irq_dump_process64_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_process64_stack,
+		.callbacks[0] = ltt_serialize_process64_stack },
+	{ "stack_arch_syscall_dump_process64_stack", MARK_NOARGS,
+		GET_CHANNEL_INDEX(cpu),
+		.probe_func = ltt_trace_process64_stack,
+		.callbacks[0] = ltt_serialize_process64_stack },
+};
+
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		result = marker_set_probe(probe_array[eID].name,
+				probe_array[eID].format,
+				probe_array[eID].probe_func, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/ltt/probes/ltt-probe-xenomai.c b/ltt/probes/ltt-probe-xenomai.c
new file mode 100644
index 0000000..bff60c3
--- /dev/null
+++ b/ltt/probes/ltt-probe-xenomai.c
@@ -0,0 +1,168 @@
+/*
+ * ltt-probe-xenomai.c
+ *
+ * Xenomai probes
+ *
+ * Philippe Gerum <rpm@xenomai.org>, April 2008
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/crc32.h>
+#include <linux/marker.h>
+#include <linux/ltt-facilities.h>
+#include <linux/ltt-tracer.h>
+
+/*
+ * BIG FAT WARNING: the Xenomai probes must be defined here exactly in
+ * the same order than declared in lttctl's facility XML description,
+ * i.e. facilities/xenomai.xml. Otherwise, weird things may
+ * happen. You have been warned.
+ */
+
+#define FACILITY_NAME "xenomai"
+
+static struct ltt_probe_data probe_array[] =
+{
+	{ "xn_nucleus_irq_enter", "irq %u", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_irq_exit", "irq %u", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_irq_attach", "irq %u name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_irq_detach", "irq %u", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_irq_enable", "irq %u", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_irq_disable", "irq %u", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_irq_affinity", "irq %u %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_watchdog", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_remote", MARK_NOARGS, GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_finalize", "thread_out %p thread_out_name %s "
+	  	"thread_in %p thread_in_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_callout", "thread %p thread_name %s hook %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_init", "thread %p thread_name %s flags %lu priority %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_start", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_restart", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_setmode", "thread %p thread_name %s clrmask %lu setmask %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_delete", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_suspend", "thread %p thread_name %s mask %lu timeout %Lu "
+	  	"timeout_mode %d wchan %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_resume", "thread %p thread_name %s mask %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_unblock", "thread %p thread_name %s state %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_renice", "thread %p thread_name %s priority %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_migrate", "thread %p thread_name %s cpu %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_fault", "thread %p thread_name %s address %lu type %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_setperiodic", "thread %p thread_name %s idate %Lu period %Lu timer %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_waitperiod", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_missedperiod", "thread %p thread_name %s overruns %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_thread_boot", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_rotate", "priority %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_rractivate", "quantum %Lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_rrdeactivate", MARK_NOARGS, GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_sigdispatch", "signals %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched", MARK_NOARGS, GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_switch", "thread_out %p thread_out_name %s "
+	  	"thread_in %p thread_in_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_fast", MARK_NOARGS, GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_addhook", "type %d routine %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_sched_removehook", "type %d routine %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_tbase_tick", "base %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_tbase_start", "base %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_tbase_stop", "base %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_tbase_adjust", "base %s delta %Lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_lostage_work", "reqnum %d comm %s pid %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_gohard", "thread %p thread_name %s comm %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_hardened", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_gorelax", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_relaxed", "thread %p thread_name %s comm %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_map", "thread %p thread_name %s pid %d priority %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_unmap", "thread %p thread_name %s pid %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_start", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_syscall_histage", "thread %p thread_name %s muxid %d muxop %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_syscall_lostage", "thread %p thread_name %s muxid %d muxop %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_shadow_exit", "thread %p thread_name %s", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_synch_sleepon", "thread %p thread_name %s synch %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_synch_wakeup_one", "thread %p thread_name %s synch %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_synch_wakeup_all", "thread %p thread_name %s synch %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_synch_flush", "synch %p reason %lu", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_synch_forget", "thread %p thread_name %s synch %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_timer_start", "timer %p base %s value %Lu interval %Lu mode %u", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_timer_stop", "timer %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_timer_expire", "timer %p", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_timer_migrate", "timer %p cpu %d", GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+	{ "xn_nucleus_timer_freeze", MARK_NOARGS, GET_CHANNEL_INDEX(cpu), _MF_DEFAULT },
+};
+
+#define NUM_PROBES (sizeof(probe_array) / sizeof(struct ltt_probe_data))
+
+static struct ltt_facility facility = {
+	.name = FACILITY_NAME,
+	.num_events = NUM_PROBES,
+	.checksum = 0,
+	.id = 0xFF,
+	.alignment = 1,	/* 1: true, 0: false */
+};
+
+static int __init probe_init(void)
+{
+	int result;
+	uint8_t eID;
+	int ret;
+
+	/* FIXME : LTTV is unable to compute this CRC (for now) */
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].name,
+				strlen(probe_array[eID].name));
+		facility.checksum =
+			crc32(facility.checksum, probe_array[eID].format,
+				strlen(probe_array[eID].format));
+
+	}
+	ret = ltt_facility_kernel_register(&facility);
+	if (ret < 0) {
+		printk(KERN_WARNING "LTT : Error in registering facility %s\n",
+			facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("LTT : Facility %s registered with id %hu\n", facility.name,
+		facility.id);
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		probe_array[eID].fID = facility.id;
+		probe_array[eID].eID = eID;
+		probe_array[eID].align = facility.alignment;
+		probe_array[eID].callbacks[0] = ltt_serialize_data;
+		result = _marker_set_probe(probe_array[eID].flags,
+				probe_array[eID].name,
+				probe_array[eID].format,
+				ltt_trace, &probe_array[eID]);
+		if (!result)
+			printk(KERN_INFO "LTT unable to register probe %s\n",
+				probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit probe_fini(void)
+{
+	uint8_t eID;
+	int err;
+
+	for (eID = 0; eID < NUM_PROBES; eID++) {
+		marker_remove_probe(probe_array[eID].name);
+	}
+	synchronize_sched();	/* Wait for probes to finish */
+	err = ltt_facility_unregister(facility.id);
+	if (err)
+		printk(KERN_WARNING
+			"LTT : Error in unregistering facility %s\n",
+			facility.name);
+}
+
+module_init(probe_init);
+module_exit(probe_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philippe Gerum");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
diff --git a/mm/filemap.c b/mm/filemap.c
index 8332c77..47ddce2 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -510,9 +510,13 @@ void fastcall wait_on_page_bit(struct page *page, int bit_nr)
 {
 	DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
 
+	MARK(mm_filemap_wait_start, "%p", page_address(page));
+
 	if (test_bit(bit_nr, &page->flags))
 		__wait_on_bit(page_waitqueue(page), &wait, sync_page,
 							TASK_UNINTERRUPTIBLE);
+
+	MARK(mm_filemap_wait_end, "%p", page_address(page));
 }
 EXPORT_SYMBOL(wait_on_page_bit);
 
diff --git a/mm/memory.c b/mm/memory.c
index ef09f0a..b8226cc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -50,6 +50,7 @@
 #include <linux/delayacct.h>
 #include <linux/init.h>
 #include <linux/writeback.h>
+#include <linux/vmalloc.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -418,6 +419,34 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
 	return pfn_to_page(pfn);
 }
 
+static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va, struct vm_area_struct *vma)
+{
+	/*
+	 * If the source page was a PFN mapping, we don't have
+	 * a "struct page" for it. We do a best-effort copy by
+	 * just copying from the original user address. If that
+	 * fails, we just zero-fill it. Live with it.
+	 */
+	if (unlikely(!src)) {
+		void *kaddr = kmap_atomic(dst, KM_USER0);
+		void __user *uaddr = (void __user *)(va & PAGE_MASK);
+
+		/*
+		 * This really shouldn't fail, because the page is there
+		 * in the page tables. But it might just be unreadable,
+		 * in which case we just give up and fill the result with
+		 * zeroes.
+		 */
+		if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
+			memset(kaddr, 0, PAGE_SIZE);
+		kunmap_atomic(kaddr, KM_USER0);
+		flush_dcache_page(dst);
+		return;
+		
+	}
+	copy_user_highpage(dst, src, va, vma);
+}
+
 /*
  * copy one vm_area from one task to the other. Assumes the page tables
  * already present in the new task to be cleared in the whole range
@@ -426,8 +455,8 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
 
 static inline void
 copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
-		pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
-		unsigned long addr, int *rss)
+	     pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
+	     unsigned long addr, int *rss, struct page *uncow_page)
 {
 	unsigned long vm_flags = vma->vm_flags;
 	pte_t pte = *src_pte;
@@ -466,6 +495,21 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 	 * in the parent and the child
 	 */
 	if (is_cow_mapping(vm_flags)) {
+#ifdef CONFIG_IPIPE
+		if (uncow_page) {
+			struct page *old_page = vm_normal_page(vma, addr, pte);
+			cow_user_page(uncow_page, old_page, addr, vma);
+			pte = mk_pte(uncow_page, vma->vm_page_prot);
+
+			if (vm_flags & VM_SHARED)
+				pte = pte_mkclean(pte);
+			pte = pte_mkold(pte);
+
+			page_dup_rmap(uncow_page);
+			rss[!!PageAnon(uncow_page)]++;
+			goto out_set_pte;
+		}
+#endif /* CONFIG_IPIPE */
 		ptep_set_wrprotect(src_mm, addr, src_pte);
 		pte = pte_wrprotect(pte);
 	}
@@ -497,12 +541,26 @@ static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 	spinlock_t *src_ptl, *dst_ptl;
 	int progress = 0;
 	int rss[2];
-
+	struct page *uncow_page = NULL;
+#ifdef CONFIG_IPIPE
+	int do_cow_break = 0;
 again:
+	if (do_cow_break) {
+		uncow_page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
+		if (!uncow_page)
+			return -ENOMEM;
+		do_cow_break = 0;
+	}
+#else
+again:
+#endif
 	rss[1] = rss[0] = 0;
 	dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl);
-	if (!dst_pte)
+	if (!dst_pte) {
+		if (uncow_page)
+			page_cache_release(uncow_page);
 		return -ENOMEM;
+	}
 	src_pte = pte_offset_map_nested(src_pmd, addr);
 	src_ptl = pte_lockptr(src_mm, src_pmd);
 	spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
@@ -524,7 +582,26 @@ again:
 			progress++;
 			continue;
 		}
-		copy_one_pte(dst_mm, src_mm, dst_pte, src_pte, vma, addr, rss);
+#ifdef CONFIG_IPIPE
+		if (likely(uncow_page == NULL) && likely(pte_present(*src_pte))) {
+			if (is_cow_mapping(vma->vm_flags)) {
+				if (((vma->vm_flags|src_mm->def_flags) & (VM_LOCKED|VM_PINNED))
+				    == (VM_LOCKED|VM_PINNED)) {
+					arch_leave_lazy_mmu_mode();
+					spin_unlock(src_ptl);
+					pte_unmap_nested(src_pte);
+					add_mm_rss(dst_mm, rss[0], rss[1]);
+					pte_unmap_unlock(dst_pte, dst_ptl);
+					cond_resched();
+					do_cow_break = 1;
+					goto again;
+				}
+			}
+		}
+#endif
+		copy_one_pte(dst_mm, src_mm, dst_pte, src_pte,
+			     vma, addr, rss, uncow_page);
+		uncow_page = NULL;
 		progress += 8;
 	} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
 
@@ -1441,34 +1518,6 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
 	return pte;
 }
 
-static inline void cow_user_page(struct page *dst, struct page *src, unsigned long va, struct vm_area_struct *vma)
-{
-	/*
-	 * If the source page was a PFN mapping, we don't have
-	 * a "struct page" for it. We do a best-effort copy by
-	 * just copying from the original user address. If that
-	 * fails, we just zero-fill it. Live with it.
-	 */
-	if (unlikely(!src)) {
-		void *kaddr = kmap_atomic(dst, KM_USER0);
-		void __user *uaddr = (void __user *)(va & PAGE_MASK);
-
-		/*
-		 * This really shouldn't fail, because the page is there
-		 * in the page tables. But it might just be unreadable,
-		 * in which case we just give up and fill the result with
-		 * zeroes.
-		 */
-		if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
-			memset(kaddr, 0, PAGE_SIZE);
-		kunmap_atomic(kaddr, KM_USER0);
-		flush_dcache_page(dst);
-		return;
-
-	}
-	copy_user_highpage(dst, src, va, vma);
-}
-
 /*
  * This routine handles present pages, when users try to write
  * to a shared page. It is done by copying the page to a new address
@@ -2000,6 +2049,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
 	delayacct_set_flag(DELAYACCT_PF_SWAPIN);
 	page = lookup_swap_cache(entry);
 	if (!page) {
+		MARK(mm_swap_in, "%lu", address);
 		grab_swap_token(); /* Contend for token _before_ read-in */
  		swapin_readahead(entry, address, vma);
  		page = read_swap_cache_async(entry, vma, address);
@@ -2448,30 +2498,44 @@ unlock:
 int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 		unsigned long address, int write_access)
 {
+	int res;
 	pgd_t *pgd;
 	pud_t *pud;
 	pmd_t *pmd;
 	pte_t *pte;
 
+	MARK(mm_handle_fault_entry, "%lu %ld", address, KSTK_EIP(current));
+
 	__set_current_state(TASK_RUNNING);
 
 	count_vm_event(PGFAULT);
 
-	if (unlikely(is_vm_hugetlb_page(vma)))
-		return hugetlb_fault(mm, vma, address, write_access);
+	if (unlikely(is_vm_hugetlb_page(vma))) {
+		res = hugetlb_fault(mm, vma, address, write_access);
+		goto end;
+	}
 
 	pgd = pgd_offset(mm, address);
 	pud = pud_alloc(mm, pgd, address);
-	if (!pud)
-		return VM_FAULT_OOM;
+	if (!pud) {
+		res = VM_FAULT_OOM;
+		goto end;
+	}
 	pmd = pmd_alloc(mm, pud, address);
-	if (!pmd)
-		return VM_FAULT_OOM;
+	if (!pmd) {
+		res = VM_FAULT_OOM;
+		goto end;
+	}
 	pte = pte_alloc_map(mm, pmd, address);
-	if (!pte)
-		return VM_FAULT_OOM;
+	if (!pte) {
+		res = VM_FAULT_OOM;
+		goto end;
+	}
 
-	return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
+	res = handle_pte_fault(mm, vma, address, pte, pmd, write_access);
+end:
+	MARK(mm_handle_fault_exit, MARK_NOARGS);
+	return res;
 }
 
 EXPORT_SYMBOL_GPL(__handle_mm_fault);
@@ -2692,3 +2756,110 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
 
 	return buf - old_buf;
 }
+
+#ifdef CONFIG_IPIPE
+
+static inline int ipipe_pin_pte_range(struct mm_struct *mm, pmd_t *pmd,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	spinlock_t *ptl;
+	pte_t *pte;
+	
+	do {
+		pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+		if (!pte)
+			continue;
+
+		if (!pte_present(*pte)) {
+			pte_unmap_unlock(pte, ptl);
+			continue;
+		}
+
+		if (do_wp_page(mm, vma, addr, pte, pmd, ptl, *pte) == VM_FAULT_OOM)
+			return -ENOMEM;
+	} while (addr += PAGE_SIZE, addr != end);
+	return 0;
+}
+
+static inline int ipipe_pin_pmd_range(struct mm_struct *mm, pud_t *pud,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+			continue;
+		if (ipipe_pin_pte_range(mm, pmd, vma, addr, next))
+			return -ENOMEM;
+	} while (pmd++, addr = next, addr != end);
+	return 0;
+}
+
+static inline int ipipe_pin_pud_range(struct mm_struct *mm, pgd_t *pgd,
+				      struct vm_area_struct *vma,
+				      unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pud_t *pud;
+
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+			continue;
+		if (ipipe_pin_pmd_range(mm, pud, vma, addr, next))
+			return -ENOMEM;
+	} while (pud++, addr = next, addr != end);
+	return 0;
+}
+
+int ipipe_disable_ondemand_mappings(struct task_struct *tsk)
+{
+	unsigned long addr, next, end;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+	int result = 0;
+	pgd_t *pgd;
+
+	mm = get_task_mm(tsk);
+	if (!mm)
+		return -EPERM;
+
+	down_write(&mm->mmap_sem);
+	if (mm->def_flags & VM_PINNED)
+		goto done_mm;
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (!is_cow_mapping(vma->vm_flags))
+			continue;
+
+		addr = vma->vm_start;
+		end = vma->vm_end;
+		
+		pgd = pgd_offset(mm, addr);
+		do {
+			next = pgd_addr_end(addr, end);
+			if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+				continue;
+			if (ipipe_pin_pud_range(mm, pgd, vma, addr, next)) {
+				result = -ENOMEM;
+				goto done_mm;
+			}
+		} while (pgd++, addr = next, addr != end);
+	}
+	mm->def_flags |= VM_PINNED;
+
+  done_mm:
+	up_write(&mm->mmap_sem);
+	mmput(mm);
+	return result;
+}
+
+EXPORT_SYMBOL(ipipe_disable_ondemand_mappings);
+
+#endif
diff --git a/mm/mlock.c b/mm/mlock.c
index 3446b7e..c67382d 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -162,10 +162,10 @@ asmlinkage long sys_munlock(unsigned long start, size_t len)
 static int do_mlockall(int flags)
 {
 	struct vm_area_struct * vma, * prev = NULL;
-	unsigned int def_flags = 0;
+	unsigned int def_flags = current->mm->def_flags & VM_PINNED;
 
 	if (flags & MCL_FUTURE)
-		def_flags = VM_LOCKED;
+		def_flags |= VM_LOCKED;
 	current->mm->def_flags = def_flags;
 	if (flags == MCL_FUTURE)
 		goto out;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 2c606cc..178019e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -490,6 +490,8 @@ static void __free_pages_ok(struct page *page, unsigned int order)
 	int i;
 	int reserved = 0;
 
+	MARK(mm_page_free, "%u %p", order, page_address(page));
+
 	for (i = 0 ; i < (1 << order) ; ++i)
 		reserved += free_pages_check(page + i);
 	if (reserved)
@@ -1386,6 +1388,7 @@ fastcall unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
 	page = alloc_pages(gfp_mask, order);
 	if (!page)
 		return 0;
+	MARK(mm_page_alloc, "%u %p", order, page_address(page));
 	return (unsigned long) page_address(page);
 }
 
diff --git a/mm/page_io.c b/mm/page_io.c
index dbffec0..10f85cf 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -122,6 +122,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
 		rw |= (1 << BIO_RW_SYNC);
 	count_vm_event(PSWPOUT);
 	set_page_writeback(page);
+	MARK(mm_swap_out, "%p", page_address(page));
 	unlock_page(page);
 	submit_bio(rw, bio);
 out:
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 86897ee..c6076ff 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -156,6 +156,7 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
 		if (err)
 			break;
 	} while (pgd++, addr = next, addr != end);
+	__ipipe_pin_range_globally((unsigned long) area->addr, end);
 	flush_cache_vmap((unsigned long) area->addr, end);
 	return err;
 }
diff --git a/net/core/dev.c b/net/core/dev.c
index e660cb5..681a335 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1453,6 +1453,8 @@ int dev_queue_xmit(struct sk_buff *skb)
 	      		goto out_kfree_skb;
 
 gso:
+	MARK(net_dev_xmit, "%p %2b", skb, skb->protocol);
+
 	spin_lock_prefetch(&dev->queue_lock);
 
 	/* Disable soft irqs for various locks below. Also 
@@ -1785,6 +1787,8 @@ int netif_receive_skb(struct sk_buff *skb)
 
 	__get_cpu_var(netdev_rx_stat).total++;
 
+	MARK(net_dev_receive, "%p %2b", skb, skb->protocol);
+
 	skb->h.raw = skb->nh.raw = skb->data;
 	skb->mac_len = skb->nh.raw - skb->mac.raw;
 
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 480ace9..fdb6634 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -260,6 +260,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 		struct in_ifaddr **ifap1 = &ifa1->ifa_next;
 
 		while ((ifa = *ifap1) != NULL) {
+			MARK(net_del_ifa, "%s", ifa->ifa_label);
 			if (!(ifa->ifa_flags & IFA_F_SECONDARY) && 
 			    ifa1->ifa_scope <= ifa->ifa_scope)
 				last_prim = ifa;
@@ -370,6 +371,8 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
 			}
 			ifa->ifa_flags |= IFA_F_SECONDARY;
 		}
+		MARK(net_insert_ifa, "%s %4b", ifa->ifa_label,
+			ifa->ifa_address);
 	}
 
 	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
diff --git a/net/socket.c b/net/socket.c
index 4e39631..f403e4e 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -572,6 +572,10 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 	struct sock_iocb siocb;
 	int ret;
 
+	MARK(net_socket_sendmsg, "%p %d %d %d %zu",
+		sock, sock->sk->sk_family, sock->sk->sk_type,
+		sock->sk->sk_protocol, size);
+
 	init_sync_kiocb(&iocb, NULL);
 	iocb.private = &siocb;
 	ret = __sock_sendmsg(&iocb, sock, msg, size);
@@ -624,7 +628,12 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
 	struct sock_iocb siocb;
 	int ret;
 
-	init_sync_kiocb(&iocb, NULL);
+	MARK(net_socket_recvmsg, "%p %d %d %d %zu",
+		sock, sock->sk->sk_family, sock->sk->sk_type,
+		sock->sk->sk_protocol, size);
+
+        init_sync_kiocb(&iocb, NULL);
+
 	iocb.private = &siocb;
 	ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
 	if (-EIOCBQUEUED == ret)
@@ -1189,6 +1198,10 @@ asmlinkage long sys_socket(int family, int type, int protocol)
 	if (retval < 0)
 		goto out_release;
 
+	MARK(net_socket_create, "%p %d %d %d %d",
+		sock, sock->sk->sk_family, sock->sk->sk_type,
+		sock->sk->sk_protocol, retval);
+
 out:
 	/* It may be already another descriptor 8) Not kernel problem. */
 	return retval;
@@ -1962,6 +1975,8 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
 	a0 = a[0];
 	a1 = a[1];
 
+	MARK(net_socket_call, "%d %lu", call, a0);
+
 	switch (call) {
 	case SYS_SOCKET:
 		err = sys_socket(a0, a1, a[2]);
