[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");