=============================================
fast-timestamps-04.12.10.patch: 

This patch implements a fast timestamp API for i386 and ppc32,
close to that specified in the CELF draft spec.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> for CELF
---

 arch/i386/oprofile/Kconfig   |   19 +++++++++
 arch/ppc/oprofile/Kconfig    |   19 +++++++++
 include/asm-i386/timestamp.h |   84 +++++++++++++++++++++++++++++++++++++++++++
 include/asm-ppc/timestamp.h  |   83 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/timestamp.h    |   57 +++++++++++++++++++++++++++++
 5 files changed, 262 insertions(+)


diff -pruN -X ../cvs-admin/dontdiff tag_LINUX_2_6_9/arch/i386/oprofile/Kconfig branch_FAST_TIMESTAMPS/arch/i386/oprofile/Kconfig
--- tag_LINUX_2_6_9/arch/i386/oprofile/Kconfig	2004-04-29 18:09:42.000000000 -0700
+++ branch_FAST_TIMESTAMPS/arch/i386/oprofile/Kconfig	2004-10-26 15:58:16.000000000 -0700
@@ -19,5 +19,24 @@ config OPROFILE
 
 	  If unsure, say N.
 
+config FAST_TIMESTAMPS
+	bool "Enable fast timestamp support"
+	depends on PROFILING
+	default n
+	help
+	  This option enables kernel support for high resolution timestamps.
+	  This feature is not useful in itself, but is used as a generic
+	  timing interface by other in-kernel profiling routines.
+
+	  If unsure, say N.
+
+config TIMESTAMP_CONSTANT
+	int "timestamp constant" if FAST_TIMESTAMPS
+	default 0
+	help
+	  For the i386 architecture, this value is the CPU frequency in kHz.  To
+	  determine the correct value, look in dmsg or '/proc/cpuinfo' for the
+	  CPU frequency in MHz and multiply by 1000.  Use that value here.
+
 endmenu
 
diff -pruN -X ../cvs-admin/dontdiff tag_LINUX_2_6_9/arch/ppc/oprofile/Kconfig branch_FAST_TIMESTAMPS/arch/ppc/oprofile/Kconfig
--- tag_LINUX_2_6_9/arch/ppc/oprofile/Kconfig	2004-08-04 13:29:17.000000000 -0700
+++ branch_FAST_TIMESTAMPS/arch/ppc/oprofile/Kconfig	2004-10-26 15:59:03.000000000 -0700
@@ -19,5 +19,24 @@ config OPROFILE
 
 	  If unsure, say N.
 
+config FAST_TIMESTAMPS
+	bool "Enable fast timestamp support"
+	depends on PROFILING
+	default n
+	help
+	  This option enables kernel support for high resolution timestamps.
+	  This feature is used as a generic timing interface by in-kernel 
+	  profiling routines.
+
+	  If unsure, say N.
+
+config TIMESTAMP_CONSTANT
+	int "timestamp constant" if FAST_TIMESTAMPS
+	default 0
+	help
+	  For the ppc architecture, this value is the CPU frequency in kHz.  To
+	  determine the correct value, look in dmsg or '/proc/cpuinfo' for the
+	  CPU frequency in MHz and multiply by 1000.  Use that value here.
+
 endmenu
 
diff -pruN -X ../cvs-admin/dontdiff tag_LINUX_2_6_9/include/asm-i386/timestamp.h branch_FAST_TIMESTAMPS/include/asm-i386/timestamp.h
--- tag_LINUX_2_6_9/include/asm-i386/timestamp.h	1969-12-31 16:00:00.000000000 -0800
+++ branch_FAST_TIMESTAMPS/include/asm-i386/timestamp.h	2004-09-17 13:48:03.000000000 -0700
@@ -0,0 +1,84 @@
+/*
+   include/asm-i386/timestamp.h
+
+   A cross platform general use high-res timestamp.
+   This i386 implementation uses the Pentium processor's
+   time-stamp counter.
+
+   geoffrey.levand@am.sony.com
+*/
+
+#if !defined(_ASM_I386_TIMESTAMPS_H)
+#define _ASM_I386_TIMESTAMPS_H
+
+#include <linux/config.h>
+#include <asm/msr.h>
+
+struct timestamp
+{
+	unsigned low;
+	unsigned high;
+};
+
+#if defined(CONFIG_FAST_TIMESTAMPS)
+# if !defined(CONFIG_X86_TSC)
+#  warning TSC support not configured into kernel.
+# else
+
+static inline void
+timestamp_store (struct timestamp* ts)
+{
+	rdtsc(ts->low, ts->high);
+}
+
+static inline void
+timestamp_to_timeval (const struct timestamp* ts, struct timeval* tv)
+{
+	/* CONFIG_TIMESTAMP_CONSTANT = cpu freq in kHz */
+	/* scale_factor = 16,  OK for 16MHz - 68.7GHz clock */
+	static const unsigned scaled_freq = ((unsigned)CONFIG_TIMESTAMP_CONSTANT / 2) * 125;
+	unsigned long long scaled_ticks;
+	unsigned long long remainder;
+
+	if(CONFIG_TIMESTAMP_CONSTANT > 68719476 || CONFIG_TIMESTAMP_CONSTANT < 16000)
+	{
+		printk(KERN_ERR "%s(%d): bad value for CONFIG_TIMESTAMP_CONSTANT: %u.\n" , __FILE__,  __LINE__, CONFIG_TIMESTAMP_CONSTANT);
+		return;
+	}
+
+	scaled_ticks = ((unsigned long long)ts->high << (32 - 4)) | (unsigned long long)(ts->low >> 4);
+	remainder = do_div(scaled_ticks, scaled_freq);
+	tv->tv_sec = (time_t)(unsigned)scaled_ticks;
+
+	scaled_ticks = remainder * 1000000;
+	do_div(scaled_ticks, scaled_freq);
+	tv->tv_usec = (suseconds_t)(unsigned)scaled_ticks;
+}
+# endif /* CONFIG_X86_TSC */
+
+# if defined(FAST_TIMESTAMPS_DEBUG) /* for debugging */
+static inline unsigned short
+timestamp_high_word (unsigned x) {return (unsigned short)(((unsigned)x >> 16) & 0xffff);}
+static inline unsigned short
+timestamp_low_word (unsigned x) {return (unsigned short)(unsigned)x;}
+
+static inline int
+timestamp_to_str (const struct timestamp* ts, char* str)
+{
+	struct timeval tv;
+	char* put = str;
+
+	timestamp_to_timeval(ts, &tv);
+
+	put += sprintf(put, "timestamp: %4.4x_%4.4x_%4.4x_%4.4x (%16.16llu) => %5u:%06u",
+		timestamp_high_word(ts->high), timestamp_low_word(ts->high),
+		timestamp_high_word(ts->low), timestamp_low_word(ts->low),
+		((unsigned long long)ts->high << 32) | (unsigned long long)ts->low,
+		(unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
+
+	return put - str;
+}
+# endif /* defined(FAST_TIMESTAMPS_DEBUG) */
+
+#endif /* defined(CONFIG_FAST_TIMESTAMPS) */
+#endif
diff -pruN -X ../cvs-admin/dontdiff tag_LINUX_2_6_9/include/asm-ppc/timestamp.h branch_FAST_TIMESTAMPS/include/asm-ppc/timestamp.h
--- tag_LINUX_2_6_9/include/asm-ppc/timestamp.h	1969-12-31 16:00:00.000000000 -0800
+++ branch_FAST_TIMESTAMPS/include/asm-ppc/timestamp.h	2004-09-17 13:48:03.000000000 -0700
@@ -0,0 +1,83 @@
+/*
+   include/asm-ppc/timestamp.h
+
+   A cross platform general use high-res timestamp.
+   This ppc implementation uses the ppc processor's
+   time base register.
+
+   geoffrey.levand@am.sony.com
+*/
+
+#if !defined(_ASM_PPC_TIMESTAMPS_H)
+#define _ASM_PPC_TIMESTAMPS_H
+
+#include <linux/config.h>
+#include <asm/time.h>
+
+struct timestamp
+{
+	unsigned low;
+	unsigned high;
+};
+
+#if defined(CONFIG_FAST_TIMESTAMPS)
+static inline void
+timestamp_store (struct timestamp* ts)
+{
+	do
+	{
+		ts->high = get_tbu();
+		ts->low = get_tbl();
+	} while(get_tbu() != ts->high);
+}
+
+static inline void
+timestamp_to_timeval (const struct timestamp* ts, struct timeval* tv)
+{
+	/* CONFIG_TIMESTAMP_CONSTANT = cpu freq in kHz */
+	/* scale_factor = 16,  OK for 16MHz - 68.7GHz clock */
+	static const unsigned scaled_freq = ((unsigned)CONFIG_TIMESTAMP_CONSTANT / 2) * 125;
+	unsigned long long scaled_ticks;
+	unsigned long long remainder;
+
+	if(CONFIG_TIMESTAMP_CONSTANT > 68719476 || CONFIG_TIMESTAMP_CONSTANT < 16000)
+	{
+		printk(KERN_ERR "%s(%d): bad value for CONFIG_TIMESTAMP_CONSTANT: %u.\n" , __FILE__,  __LINE__, CONFIG_TIMESTAMP_CONSTANT);
+		return;
+	}
+
+	scaled_ticks = ((unsigned long long)ts->high << (32 - 4)) | (unsigned long long)(ts->low >> 4);
+	remainder = do_div(scaled_ticks, scaled_freq);
+	tv->tv_sec = (time_t)(unsigned)scaled_ticks;
+
+	scaled_ticks = remainder * 1000000;
+	do_div(scaled_ticks, scaled_freq);
+	tv->tv_usec = (suseconds_t)(unsigned)scaled_ticks;
+}
+
+# if defined(FAST_TIMESTAMPS_DEBUG) /* for debugging */
+static inline unsigned short
+timestamp_high_word (unsigned x) {return (unsigned short)(((unsigned)x >> 16) & 0xffff);}
+static inline unsigned short
+timestamp_low_word (unsigned x) {return (unsigned short)(unsigned)x;}
+
+static inline int
+timestamp_to_str (const struct timestamp* ts, char* str)
+{
+	struct timeval tv;
+	char* put = str;
+
+	timestamp_to_timeval(ts, &tv);
+
+	put += sprintf(put, "timestamp: %4.4x_%4.4x_%4.4x_%4.4x (%16.16llu) => %5u:%06u",
+		timestamp_high_word(ts->high), timestamp_low_word(ts->high),
+		timestamp_high_word(ts->low), timestamp_low_word(ts->low),
+		((unsigned long long)ts->high << 32) | (unsigned long long)ts->low,
+		(unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
+
+	return put - str;
+}
+# endif /* defined(FAST_TIMESTAMPS_DEBUG) */
+
+#endif /* defined(CONFIG_FAST_TIMESTAMPS) */
+#endif
diff -pruN -X ../cvs-admin/dontdiff tag_LINUX_2_6_9/include/linux/timestamp.h branch_FAST_TIMESTAMPS/include/linux/timestamp.h
--- tag_LINUX_2_6_9/include/linux/timestamp.h	1969-12-31 16:00:00.000000000 -0800
+++ branch_FAST_TIMESTAMPS/include/linux/timestamp.h	2004-09-17 13:48:02.000000000 -0700
@@ -0,0 +1,57 @@
+/*
+   include/timestamp.h
+
+   A cross platform general use high-res timestamp.
+   This file contains common routines.
+
+   geoffrey.levand@am.sony.com
+*/
+
+#if !defined(_LINUX_TIMESTAMPS_H)
+#define _LINUX_TIMESTAMPS_H
+
+#include <linux/config.h>
+#include <linux/time.h>
+#include <asm/timestamp.h>
+
+#if defined(CONFIG_FAST_TIMESTAMPS)
+
+# if defined(FAST_TIMESTAMPS_DEBUG) /* for debugging */
+
+static inline void
+timestamp_print (const struct timestamp* ts)
+{
+	char* buf = kmalloc(512, GFP_KERNEL);
+
+	timestamp_to_str(ts, buf);
+	printk(KERN_INFO "%s\n", buf);
+	kfree(buf);
+}
+
+static inline void
+timestamp_dump (void)
+{
+	struct timestamp ts;
+
+	timestamp_store(&ts);
+	timestamp_print(&ts);
+}
+
+# endif /* defined(FAST_TIMESTAMPS_DEBUG) */
+
+#else /* defined(CONFIG_FAST_TIMESTAMPS) */
+
+static inline void
+timestamp_store (struct timestamp* ts)
+{
+	(void)0;
+}
+
+static inline void
+timestamp_to_timeval (const struct timestamp* ts, struct timeval* tv)
+{
+	tv->tv_sec = tv->tv_usec = 0;
+}
+
+#endif /* defined(CONFIG_FAST_TIMESTAMPS) */
+#endif
