[PATCH] Initial support for Niagara T1 performance counters

From: Elad Lahav
Date: Thu Sep 11 2008 - 17:22:36 EST


The patch handles performance counter overflow traps, which are
currently being ignored.
A trap with type 0x4f is generated by either a level-15 interrupt, or,
if the processor interrupt level is smaller than 15, by the overflow of
a performance counter (either the low or high parts). Currently, the
kernel ignores the former, and handles only the latter. The patch checks
the previous value of PIL and, if smaller than 15, increments a 64-bit
per-cpu counter. The counter is used to count both types of overflows,
being divided into two 32 bit values. The counter is exported, so that
kernel modules can use it to keep track of 64-bit performance counter
values.
A sample module, which uses the overflow counters, can be found on:
http://www.cs.uwaterloo.ca/~elahav/pcount.c
The module uses a procfs entry (/proc/pcount) that enables users to both
programme the counters (start, stop, reset, configure event), as well as
get a snapshot of the current value of all counters.

Notes:
1. I have tried to be as unintrusive as possible. The code is only
enabled if a config option is turned on, and the option is marked as
EXPERIMENTAL.
2. The way in which the previous PIL value is extracted from the stored
TSTATE register is based on my interpretation of the code in etrap.S. I
hope it is correct (seems to be working, though).
3. I'm not sure about the need to manually reset the PCR overflow flags
- see comment in the code (again, seems to be working).


Signed-off-by: Elad Lahav <elad_lahav@xxxxxxxxxxxxxxxxxxxxx>
---
diff -r -u linux-2.6.26.5/arch/sparc64/Kconfig linux-2.6.26.5-t1pc/arch/sparc64/Kconfig
--- linux-2.6.26.5/arch/sparc64/Kconfig 2008-09-08 13:40:20.000000000 -0400
+++ linux-2.6.26.5-t1pc/arch/sparc64/Kconfig 2008-09-11 10:24:47.000000000 -0400
@@ -397,6 +397,15 @@

NOTE: This option WILL override the PROM bootargs setting!

+config T1_PERF_COUNTERS
+ bool "Support for performance counters on the Niagara T1 (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && SPARC64
+ default n
+ help
+ Each virtual processor on the T1 has its own performance counter
+ unit, composed of two 32 bit counters.
+ Say Y to enable support for programming and reading these counters.
+
source "net/Kconfig"

source "drivers/Kconfig"
diff -r -u linux-2.6.26.5/arch/sparc64/kernel/irq.c linux-2.6.26.5-t1pc/arch/sparc64/kernel/irq.c
--- linux-2.6.26.5/arch/sparc64/kernel/irq.c 2008-09-08 13:40:20.000000000 -0400
+++ linux-2.6.26.5-t1pc/arch/sparc64/kernel/irq.c 2008-09-11 16:19:44.000000000 -0400
@@ -703,6 +703,53 @@
__asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
}

+#ifdef CONFIG_T1_PERF_COUNTERS
+/**
+ * pic_overflows holds two 32 bit values. The lower one keeps track of the
+ * overflows of the programmable counter (PIC.l), and the higher of the
+ * overflows of the instruction counter (PIC.h).
+ */
+DEFINE_PER_CPU(u64, pic_overflows);
+EXPORT_PER_CPU_SYMBOL(pic_overflows);
+
+/**
+ * Handles a performance counter overflow trap.
+ * The trap occurs when either the high or the low halves of the counter (or
+ * both) overflow. This is indicated by a disrupting trap on SOFTINT 15 (0x4f),
+ * whike PIL < 15.
+ */
+static void handle_pic_overflow(void)
+{
+ u64 pcr;
+
+ /*
+ * Get the current value of the control register.
+ */
+ __asm__ __volatile__("rd %%pcr, %0" : "=r" (pcr));
+
+ /*
+ * Check the overflow flags.
+ * Bit 9 is set if the high half of the counter has overflowed.
+ * Bit 8 is set if the low half of the counter has overflowed.
+ */
+ if (pcr & (1ULL << 9))
+ __get_cpu_var(pic_overflows) += (1ULL << 32);
+ if (pcr & (1ULL << 8))
+ __get_cpu_var(pic_overflows)++;
+
+ /*
+ * Reset the overflow flags.
+ * TODO: The manual does not mention that the overflow flags need to be
+ * reset manually. This is probably safe, though, as this function is
+ * called with PIL=15, so that another overflow trap cannot happen in
+ * the meantime.
+ */
+ pcr &= ~(3ULL << 8);
+ __asm__ __volatile__("wr %0, %%g0, %%pcr" : : "r"(pcr));
+}
+
+#endif /* CONFIG_T1_PERF_COUNTERS */
+
void handler_irq(int irq, struct pt_regs *regs)
{
unsigned long pstate, bucket_pa;
@@ -714,6 +761,28 @@
old_regs = set_irq_regs(regs);
irq_enter();

+#ifdef CONFIG_T1_PERF_COUNTERS
+ /*
+ * SOFTINT 15 is shared with the PIC overflow trap.
+ * This is indicated by the PIL register having a value < 15 (i.e.,
+ * an interrupt of level 15 is blocked).
+ */
+ if (irq == 15) {
+ unsigned long pil;
+
+ /*
+ * PIL is set to 15 by the trap entry routine.
+ * To find out the value of PIL when the trap was taken, we
+ * need to look into bits 20-23 of the saved TSTATE register.
+ */
+ pil = (regs->tstate & (0xf << 20)) >> 20;
+ if (pil < 15) {
+ handle_pic_overflow();
+ goto exit_irq;
+ }
+ }
+#endif /* CONFIG_T1_PERF_COUNTERS */
+
/* Grab an atomic snapshot of the pending IVECs. */
__asm__ __volatile__("rdpr %%pstate, %0\n\t"
"wrpr %0, %3, %%pstate\n\t"
@@ -745,6 +814,7 @@

restore_hardirq_stack(orig_sp);

+exit_irq:
irq_exit();
set_irq_regs(old_regs);
}
diff -r -u linux-2.6.26.5/include/asm-sparc64/irq.h linux-2.6.26.5-t1pc/include/asm-sparc64/irq.h
--- linux-2.6.26.5/include/asm-sparc64/irq.h 2008-09-08 13:40:20.000000000 -0400
+++ linux-2.6.26.5-t1pc/include/asm-sparc64/irq.h 2008-09-11 10:37:40.000000000 -0400
@@ -94,4 +94,8 @@
extern void *softirq_stack[NR_CPUS];
#define __ARCH_HAS_DO_SOFTIRQ

+#ifdef CONFIG_T1_PERF_COUNTERS
+DECLARE_PER_CPU(u64, pic_overflows);
+#endif /* CONFIG_T1_PERF_COUNTERS */
+
#endif

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/