[PATCH] LTT for SH4

"Giuseppe Cavallaro" <[email protected]>
Newsgroups gmane.linux.kernel.tracing
Message-ID <[email protected]>
Hi All,
I'm working on LTT for SH4 architecture (*).
In attachment you will find:
- lttng-sh_timestamp.patch
        It reviews the include/asm-sh/ltt.h file (adding timestamp mechanism
via TMU).
- lttng-0.9.5-sh_ptrace.patch:
        It marks the do_syscall_trace function within ptrace.c file.
- lttng-0.9.5-probe-kernel_arch_sh.patch

I cannot actually test these patches on the latest kernels.
In any case, this code, added in the 2.6.17 tree, seems to start working.

Hoping that could be useful.
Cheers,
   Giuseppe

(*) using a kernel 2.6.17 plus LTTng-0.9.5 patches.

_______________________________________________
Ltt-dev mailing list
[email protected]
http://listserv.shafik.org/mailman/listinfo/ltt-dev
lttng-0.9.5-sh_ptrace.patch (application/octet-stream, 1.5 KB)
This marks the do_syscall_trace function within the ptrace.c file

--- linux-2.6.21/arch/sh/kernel/ptrace.c.orig	2007-07-03 15:49:05.000000000 +0200
+++ linux-2.6.21/arch/sh/kernel/ptrace.c	2007-07-03 15:50:14.000000000 +0200
@@ -264,10 +264,23 @@ long arch_ptrace(struct task_struct *chi
 	return ret;
 }
 
+#ifdef CONFIG_LTT
+asmlinkage void do_syscall_trace(struct pt_regs *regs, int traceid)
+#else
 asmlinkage void do_syscall_trace(void)
+#endif
 {
 	struct task_struct *tsk = current;
 
+#ifdef CONFIG_LTT
+	if (traceid) {
+		MARK(kernel_arch_syscall_entry, "%d %ld", regs->regs[3],
+			instruction_pointer(regs));
+	} else {
+		MARK(kernel_arch_syscall_exit, MARK_NOARGS);
+	}
+#endif
+
 	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
 	    !test_thread_flag(TIF_SINGLESTEP))
 		return;
--- linux-2.6.21/arch/sh/kernel/entry-common.S.orig	2007-07-03 15:48:10.000000000 +0200
+++ linux-2.6.21/arch/sh/kernel/entry-common.S	2007-07-03 15:48:58.000000000 +0200
@@ -234,6 +234,10 @@ syscall_exit_work:
 #endif
 	sti
 	! XXX setup arguments...
+#ifdef CONFIG_LTT
+	mov     r15, r4
+	mov     #0, r5			! trace entry [0]
+#endif
 	mov.l	4f, r0			! do_syscall_trace
 	jsr	@r0
 	 nop
@@ -242,6 +246,10 @@ syscall_exit_work:
 
 	.align	2
 syscall_trace_entry:
+#ifdef CONFIG_LTT
+	mov     r15, r4		! pass stacked regs as arg
+	mov     #1, r5		! trace entry [1]
+#endif
 	!                     	Yes it is traced.
 	! XXX setup arguments...
 	mov.l	4f, r11		! Call do_syscall_trace which notifies
lttng-sh_timestamp.patch (application/octet-stream, 4.1 KB)
This patch adds the timestamping mechanism in the ltt.h arch header file.
The new timestamp functions use the TMU channel 1.

--- linux/include/asm-sh/ltt.h.orig	2007-07-03 15:30:12.000000000 +0200
+++ linux/include/asm-sh/ltt.h	2007-07-03 15:34:15.000000000 +0200
@@ -1 +1,125 @@
-#include <asm-generic/ltt.h>
+/*
+ * SH definitions for tracing system
+ * Author Giuseppe Cavallaro <[email protected]>
+ * 
+ * It implements timestamp functions using the TMU channel 1.
+ * The ltt_init_timer, invoked during the kernel boot, 
+ * inits the TMU channel and setups the IRQ line.
+ * The IRQ hander is only used for managing counter underflow.
+ * The ltt_get_timestamp64 invokes the ltt_get_timestamp32
+ * because the HW doesn't have 64 bit timestamp counter.
+ */
+
+#ifndef _ASM_SH_LTT_H
+#define _ASM_SH_LTT_H
+
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/seqlock.h>
+#include <asm/timer.h>
+#include <asm/rtc.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/clock.h>
+
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_SH
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
+
+#undef LTT_HAS_TSC
+static int ltt_underflow;
+
+/* Using the TMU channel 1 for getting clock */
+#define TMU_TSTR_STR1   0x02    	/* Bit to turn on TMU1 */
+#define TMU1_TCOR       0xffd80014      /* Long access */
+#define TMU1_TCNT       0xffd80018      /* Long access */
+#define TMU1_TCR        0xffd8001c      /* Word access */
+#define TMU1_TCR_INIT   0x0000  	/* Clock/4, rising edge; no interrupt */
+#define TMU1_TCR_UNIE   (1<<5)  /* Bit to enable underflow interrupts */
+#define TMU1_TCR_UNF    (1<<8)  /* Status flag to indicated underflow occurred */
+
+/* by default, load the maximum value in the counter registers */
+static unsigned long tmu_value = 0xffffffff;
+
+static int ltt_tmu1_enable_irq(void)
+{
+	/* stop timer */
+        ctrl_outb((ctrl_inb(TMU_TSTR) & ~TMU_TSTR_STR1), TMU_TSTR);
+	/* set counter regs */
+        ctrl_outl(tmu_value, TMU1_TCOR);
+        ctrl_outl(tmu_value, TMU1_TCNT);
+	/* Enable UNF irq */
+        ctrl_outw((TMU1_TCR_INIT | TMU1_TCR_UNIE), TMU1_TCR);
+	/* start timer */
+        ctrl_outb((ctrl_inb(TMU_TSTR) | TMU_TSTR_STR1), TMU_TSTR);
+
+        return 0;
+}
+
+static inline u32 ltt_get_timestamp32(void)
+{
+        int count;
+        int t1;
+
+	/* Reading the timer counter */
+	t1 = ctrl_inl(TMU1_TCNT);
+
+	count = ltt_underflow * (tmu_value) + (tmu_value - t1);
+
+        return (unsigned long) count;
+}
+
+static inline u64 ltt_get_timestamp64(void)
+{
+	u64 ret = ltt_get_timestamp32();
+	return (ret);
+}
+
+/* This is the IRQ handler, it increments the ltt_underflow index and
+ * cleans the UNF bit in the TMU1_TCR register */
+static irqreturn_t ltt_tmu1_handler(int irq, void *p, struct pt_regs *regs)
+{
+	unsigned short timer_status;
+        ltt_underflow++;
+	/* Clear UNF bit */
+        timer_status = ctrl_inw(TMU1_TCR);
+        timer_status &= ~TMU1_TCR_UNF;
+        ctrl_outw(timer_status, TMU1_TCR);
+
+        return IRQ_HANDLED;
+}
+
+static struct irqaction tmu1_irq = {
+	.name		= "ltt_timer",
+	.handler	= ltt_tmu1_handler,
+	.flags		= SA_INTERRUPT,
+	.mask		= CPU_MASK_NONE,
+};
+
+static inline void ltt_init_timer(void)
+{
+        ltt_underflow = 0;
+
+	setup_irq(TIMER1_IRQ, &tmu1_irq);
+	ltt_tmu1_enable_irq();
+	return;
+}
+
+static inline unsigned int ltt_frequency(void)
+{
+	unsigned long rate;
+	struct clk *tmu1_clk;
+
+	/* TMU 0/1/2 clocks from module_clk */
+	tmu1_clk = clk_get("tmu0_clk");
+
+	rate = (clk_get_rate(tmu1_clk));
+	printk (KERN_DEBUG "LTT: ltt_frequency: %lu Hz\n", rate);
+
+	return (unsigned int)(rate);
+}
+
+static inline u32 ltt_freq_scale(void)
+{
+	return 1;
+}
+#endif
--- linux/arch/sh/kernel/time.c.orig	2007-07-03 15:30:36.000000000 +0200
+++ linux/arch/sh/kernel/time.c	2007-07-03 15:35:26.000000000 +0200
@@ -19,6 +19,9 @@
 #include <asm/rtc.h>
 #include <asm/timer.h>
 #include <asm/kgdb.h>
+#ifdef CONFIG_LTT
+#include <asm/ltt.h>
+#endif
 
 struct sys_timer *sys_timer;
 
@@ -320,5 +323,8 @@ void __init time_init(void)
 	if (sys_timer->dyn_tick)
 		spin_lock_init(&sys_timer->dyn_tick->lock);
 #endif
+#ifdef CONFIG_LTT
+        ltt_init_timer();
+#endif
 
 }
lttng-0.9.5-probe-kernel_arch_sh.patch (application/octet-stream, 3 KB)
This adds the kernel_arch probe functions for SH architecture.
Indeed, it is the same code used for other architectures (i.e. arm).

--- /dev/null	2007-07-03 15:14:15.628235594 +0200
+++ linux/ltt/probes/ltt-probe-kernel_arch_sh.c	2007-06-26 09:06:04.574112000 +0200
@@ -0,0 +1,106 @@
+/*
+ * ltt-probe-kernel_arch_arm.c
+ *
+ * kernel_arch probe
+ *
+ * Part of LTTng
+ *
+ * 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 arch_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 "%s LTT : Error in registering facility %s\n",
+			"SH", facility.name);
+		return ret;
+	}
+	facility.id = (uint8_t)ret;
+
+	printk("%s LTT : Facility %s registered with id %hu\n", "SH", 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 "%s LTT unable to register probe %s\n",
+				"SH", probe_array[eID].name);
+	}
+	return 0;
+}
+
+static void __exit arch_probe_exit(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
+			"%s LTT : Error in unregistering facility %s\n",
+			"SH", facility.name);
+}
+
+module_init(arch_probe_init);
+module_exit(arch_probe_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mathieu Desnoyers");
+MODULE_DESCRIPTION(FACILITY_NAME " probe");
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.