From: Stephane Eranian <eranian@hpl.hp.com>
To: linux-kernel@vger.kernel.org
Cc: Stephane Eranian <eranian@hpl.hp.com>
Subject: Re: [PATCH 5/5] powerpc perfmon2 code for review
Date: Wed, 23 Nov 2005 06:57:54 -0800 [thread overview]
Message-ID: <20051123145754.GF17228@frankl.hpl.hp.com> (raw)
In-Reply-To: <20051123145645.GE17228@frankl.hpl.hp.com>
[-- Attachment #1: Type: text/plain, Size: 829 bytes --]
Hello,
For some reasons, the original annoucement from 11/18
for this release never made it to this list.
You can download the latest packages from:
http://www.sf.net/projects/perfmon2
You need to grab:
2.6.15-rc1-git6 (kernel code)
libpfm-3.2-051118 (user library)
For convenience, I am also posting the patch directly
to the list. At this point, the patch is for review.
Please cc me on your replies because due to the volume
of traffic I am not a member of the list.
I have split the patch into 5 parts. The first part is needed on
each platform (common code). All the others are specific to
a processor architecture. There is an exception for x86-64 which
needs the i386 portion due to cross use of header files. The
patch is relative to 2.6.15-rc1-git6.
thanks.
This E-mail contains Part 5: powerpc code (PPC64)
[-- Attachment #2: perfmon-new-base-powerpc-051118.diff --]
[-- Type: text/plain, Size: 26171 bytes --]
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/Kconfig linux-2.6.15-rc1-git6/arch/powerpc/Kconfig
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/Kconfig 2005-11-18 05:16:42.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/Kconfig 2005-11-18 05:48:12.000000000 -0800
@@ -237,6 +237,18 @@
bool
depends on 4xx || 8xx || E200
default y
+
+menu "Hardware Performance Monitoring support"
+config PERFMON
+ bool "Perfmon2 performance monitoring interface"
+ default y
+ help
+ include the perfmon2 performance monitoring interface
+ in the kernel. See <http://www.hpl.hp.com/research/linux/perfmon> for
+ more details. If you're unsure, say Y.
+source "arch/powerpc/perfmon/Kconfig"
+endmenu
+
endmenu
source "init/Kconfig"
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/Makefile linux-2.6.15-rc1-git6/arch/powerpc/Makefile
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/Makefile 2005-11-18 05:16:42.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/Makefile 2005-11-18 05:48:12.000000000 -0800
@@ -132,6 +132,7 @@
arch/powerpc/platforms/
core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/
core-$(CONFIG_XMON) += arch/powerpc/xmon/
+core-$(CONFIG_PERFMON) += arch/powerpc/perfmon/
core-$(CONFIG_APUS) += arch/ppc/amiga/
drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/
drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/kernel/entry_64.S linux-2.6.15-rc1-git6/arch/powerpc/kernel/entry_64.S
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/kernel/entry_64.S 2005-11-18 05:16:42.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/kernel/entry_64.S 2005-11-18 05:48:12.000000000 -0800
@@ -603,6 +603,9 @@
b .ret_from_except_lite
1: bl .save_nvgprs
+#ifdef CONFIG_PERFMON
+ bl .ppc64_pfm_handle_work
+#endif /* CONFIG_PERFMON */
li r3,0
addi r4,r1,STACK_FRAME_OVERHEAD
bl .do_signal
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/kernel/process.c linux-2.6.15-rc1-git6/arch/powerpc/kernel/process.c
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/kernel/process.c 2005-11-18 05:16:42.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/kernel/process.c 2005-11-18 05:48:12.000000000 -0800
@@ -38,6 +38,7 @@
#include <linux/hardirq.h>
#include <linux/utsname.h>
#include <linux/kprobes.h>
+#include <linux/perfmon.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -306,7 +307,9 @@
#endif
local_irq_save(flags);
+ pfm_ctxswout(prev);
last = _switch(old_thread, new_thread);
+ pfm_ctxswin(current);
local_irq_restore(flags);
@@ -447,6 +450,7 @@
last_task_used_spe = NULL;
#endif
#endif /* CONFIG_SMP */
+ pfm_exit_thread(current);
}
void flush_thread(void)
@@ -570,6 +574,7 @@
kregs->nip = (unsigned long)ret_from_fork;
p->thread.last_syscall = -1;
#endif
+ pfm_copy_thread(p, childregs);
return 0;
}
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/kernel/systbl.S linux-2.6.15-rc1-git6/arch/powerpc/kernel/systbl.S
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/kernel/systbl.S 2005-11-18 05:16:42.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/kernel/systbl.S 2005-11-18 05:48:12.000000000 -0800
@@ -319,3 +319,15 @@
SYSCALL(inotify_init)
SYSCALL(inotify_add_watch)
SYSCALL(inotify_rm_watch)
+SYSCALL(pfm_create_context)
+SYSCALL(pfm_write_pmcs)
+SYSCALL(pfm_write_pmds)
+SYSCALL(pfm_read_pmds)
+SYSCALL(pfm_load_context)
+SYSCALL(pfm_start)
+SYSCALL(pfm_stop)
+SYSCALL(pfm_restart)
+SYSCALL(pfm_create_evtsets)
+SYSCALL(pfm_getinfo_evtsets)
+SYSCALL(pfm_delete_evtsets)
+SYSCALL(pfm_unload_context)
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/Kconfig linux-2.6.15-rc1-git6/arch/powerpc/perfmon/Kconfig
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/Kconfig 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/perfmon/Kconfig 2005-11-18 05:48:12.000000000 -0800
@@ -0,0 +1,7 @@
+config PERFMON_POWER5
+ tristate "Support for Power5 hardware performance counters"
+ depends on PERFMON
+ default m
+ help
+ Enables support for the Power 5 hardware performance counters
+ If unsure, say M.
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/Makefile linux-2.6.15-rc1-git6/arch/powerpc/perfmon/Makefile
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/perfmon/Makefile 2005-11-18 05:48:12.000000000 -0800
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PERFMON) += perfmon.o
+obj-$(CONFIG_PERFMON_POWER5) += perfmon_power5.o
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/perfmon.c linux-2.6.15-rc1-git6/arch/powerpc/perfmon/perfmon.c
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/perfmon.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/perfmon/perfmon.c 2005-11-18 05:48:12.000000000 -0800
@@ -0,0 +1,347 @@
+/*
+ * This file implements the ppc64 specific
+ * support for the perfmon2 interface
+ *
+ * Copyright (c) 2005 David Gibson, IBM Corporation.
+ *
+ * based on versions for other architectures:
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ */
+#include <linux/interrupt.h>
+#include <linux/perfmon.h>
+
+/*
+ * collect pending overflowed PMDs. Called from ctxswout_*()
+ * and from PMU interrupt handler. Must fill in set->set_povfl_pmds[]
+ * and set->set_npend_ovfls. Interrupts are masked
+ */
+static void __pfm_get_ovfl_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
+{
+ u64 new_val, wmask;
+ unsigned long *used_mask;
+ unsigned int i, max;
+
+ max = pfm_pmu_conf->max_cnt_pmd;
+ used_mask = set->set_used_pmds;
+ wmask = PFM_ONE_64 << pfm_pmu_conf->counter_width;
+
+ for (i = 0; i < max; i++) {
+ /* assume all PMD are counters */
+ if (pfm_bv_isset(used_mask, i)) {
+ new_val = pfm_arch_read_pmd(ctx, i);
+
+ DPRINT_ovfl(("pmd%u new_val=0x%lx bit=%d\n",
+ i, new_val, (new_val&wmask) ? 1 : 0));
+
+ if ((new_val & wmask) == 0) {
+ pfm_bv_set(set->set_povfl_pmds, i);
+ set->set_npend_ovfls++;
+ }
+ }
+ }
+}
+
+/*
+ * Called from pfm_ctxswout_*(). Task is guaranteed to be current.
+ * Context is locked. Interrupts are masked. Monitoring is active.
+ * PMU access is guaranteed. PMC and PMD registers are live in PMU.
+ *
+ * for per-thread:
+ * must stop monitoring for the task
+ * for system-wide:
+ * must ensure task has monitoring stopped. But monitoring may continue
+ * on the current processor
+ */
+void pfm_arch_ctxswout(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set)
+{
+ mtspr(SPRN_MMCR0, MMCR0_FC);
+
+ if (ctx->ctx_fl_system)
+ return;
+
+ /*
+ * disable lazy restore of PMC registers.
+ */
+ if (set)
+ set->set_priv_flags |= PFM_SETFL_PRIV_MOD_PMCS;
+
+ __pfm_get_ovfl_pmds(ctx, set);
+}
+
+/*
+ * Called from pfm_ctxswin_*(). Task is guaranteed to be current.
+ * set cannot be NULL. Context is locked. Interrupts are masked.
+ * Caller has already restored all PMD and PMC registers.
+ *
+ * must reactivate monitoring
+ */
+void pfm_arch_ctxswin(struct task_struct *task,
+ struct pfm_context *ctx, struct pfm_event_set *set)
+{
+ /* nothing to do will be restored correctly */
+}
+
+/*
+ * Called from pfm_stop() and pfm_ctxswin_*() when idle
+ * task and EXCL_IDLE is on.
+ *
+ * Interrupts are masked. Context is locked. Set is the active set.
+ *
+ * For per-thread:
+ * task is not necessarily current. If not current task, then
+ * task is guaranteed stopped and off any cpu. Access to PMU
+ * is not guaranteed. Interrupts are masked. Context is locked.
+ * Set is the active set.
+ *
+ * For system-wide:
+ * task is current
+ *
+ * must disable active monitoring.
+ */
+void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *aset)
+{
+ if (task != current)
+ return;
+
+ mtspr(SPRN_MMCR0, MMCR0_FC);
+}
+
+/*
+ * function called from pfm_unload_context_*(). Context is locked.
+ * interrupts are masked. task is not guaranteed to be current task.
+ * Access to PMU is not guaranteed.
+ *
+ * function must do whatever arch-specific action is required on unload
+ * of a context.
+ *
+ * called for both system-wide and per-thread. task is NULL for ssytem-wide
+ */
+void pfm_arch_unload_context(struct pfm_context *ctx, struct task_struct *task)
+{
+}
+
+/*
+ * called from pfm_start() or pfm_ctxswout_sys() when idle task and
+ * EXCL_IDLE is on.
+ *
+ * Interrupts are masked. Context is locked. Set is the active set.
+ *
+ * For per-trhead:
+ * Task is not necessarily current. If not current task, then task
+ * is guaranteed stopped and off any cpu. Access to PMU is not guaranteed.
+ *
+ * For system-wide:
+ * task is always current
+ *
+ * must enable active monitoring.
+ */
+static void __pfm_arch_start(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set)
+{
+ if (task != current)
+ return;
+
+ mtspr(SPRN_MMCR0, set->set_pmcs[0]);
+ mtspr(SPRN_MMCR1, set->set_pmcs[1]);
+ mtspr(SPRN_MMCRA, set->set_pmcs[2]);
+}
+
+void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set)
+{
+ /*
+ * mask/unmask uses start/stop mechanism, so we cannot allow
+ * while masked.
+ */
+ if (ctx->ctx_state == PFM_CTX_MASKED)
+ return;
+
+ __pfm_arch_start(task, ctx, set);
+}
+
+/*
+ * function called from pfm_switch_sets(), pfm_context_load_thread(),
+ * pfm_context_load_sys(), pfm_ctxswin_*(), pfm_switch_sets()
+ * context is locked. Interrupts are masked. set cannot be NULL.
+ * Access to the PMU is guaranteed.
+ *
+ * function must restore all PMD registers from set.
+ */
+void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
+{
+ unsigned int i;
+ unsigned int num_cnt;
+ u64 ovfl_mask, val, *pmds;
+
+ num_cnt = pfm_pmu_conf->num_pmds;
+ ovfl_mask = pfm_pmu_conf->ovfl_mask;
+ pmds = set->set_view->set_pmds;
+
+ /* start at 1 to skip TB */
+ for (i = 1; i < num_cnt; i++) {
+ val = pmds[i] & ovfl_mask;
+ pfm_arch_write_pmd(ctx, i, val);
+ }
+}
+
+/*
+ * function called from pfm_switch_sets(), pfm_context_load_thread(),
+ * pfm_context_load_sys(), pfm_ctxswin_*(), pfm_switch_sets()
+ * context is locked. Interrupts are masked. set cannot be NULL.
+ * Access to the PMU is guaranteed.
+ *
+ * function must restore all PMC registers from set, if needed.
+ */
+void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set)
+{
+ unsigned int i, num_cnt;
+
+ num_cnt = pfm_pmu_conf->num_pmcs;
+
+ /*
+ * - by default, no PMC measures anything
+ * - on ctxswout, all used PMCs are disabled (cccr cleared)
+ *
+ * we need to restore the PMC (incl enable bits) only if
+ * not masked and user issued pfm_start()
+ */
+ if (ctx->ctx_state == PFM_CTX_MASKED || ctx->ctx_fl_started == 0)
+ return;
+
+ /*
+ * restore all pmcs
+ */
+ for (i = 0; i < num_cnt; i++)
+ pfm_arch_write_pmc(ctx, i, set->set_pmcs[i]);
+}
+
+/*
+ * function called from pfm_mask_monitoring(), pfm_switch_sets(),
+ * pfm_ctxswout_*(), pfm_flush_pmds().
+ * context is locked. interrupts are masked. the set argument cannot
+ * be NULL. Access to PMU is guaranteed.
+ *
+ * function must saved PMD registers into set save area set_pmds[]
+ */
+void pfm_arch_save_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
+{
+ unsigned int i;
+ u64 ovfl_mask, *pmds, hw_val, used_mask;
+
+ ovfl_mask = pfm_pmu_conf->ovfl_mask;
+ used_mask = set->set_used_pmds[0];
+ pmds = set->set_view->set_pmds;
+
+ /*
+ * save all used pmds
+ * XXX: assume all pmds are counters
+ */
+ for (i = 0; used_mask; i++, used_mask >>=1) {
+ if (likely(used_mask & 0x1)) {
+ hw_val = pfm_arch_read_pmd(ctx, i);
+ pmds[i] = (pmds[i] & ~ovfl_mask) | (hw_val & ovfl_mask);
+ }
+ }
+}
+
+asmlinkage void pfm_intr_handler(struct pt_regs *regs)
+{
+ pfm_interrupt_handler(0, NULL, regs);
+}
+
+int pfm_arch_initialize(void)
+{
+ return 0;
+}
+
+extern void ppc64_enable_pmcs(void);
+
+void pfm_arch_init_percpu(void)
+{
+ ppc64_enable_pmcs();
+}
+
+/*
+ * function called from pfm_load_context_*(). Task is not guaranteed to be
+ * current task. If not then other task is guaranteed stopped and off any CPU.
+ * context is locked and interrupts are masked.
+ *
+ * On PFM_LOAD_CONTEXT, the interface guarantees monitoring is stopped.
+ *
+ * For system-wide task is NULL
+ */
+int pfm_arch_load_context(struct pfm_context *ctx, struct task_struct *task)
+{
+ return 0;
+}
+
+/*
+ * called from __pfm_interrupt_handler(). ctx is not NULL.
+ * ctx is locked. PMU interrupt is masked.
+ *
+ * must stop all monitoring to ensure handler has consistent view.
+ * must collect overflowed PMDs bitmask into set_povfls_pmds and
+ * set_npend_ovfls. If no interrupt detected then set_npend_ovfls
+ * must be set to zero.
+ */
+void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx)
+{
+ mtspr(SPRN_MMCR0, MMCR0_FC);
+ __pfm_get_ovfl_pmds(ctx, ctx->ctx_active_set);
+}
+
+/*
+ * unfreeze PMU from pfm_do_interrupt_handler()
+ * ctx may be NULL for spurious
+ */
+void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx)
+{
+ if (! ctx)
+ return;
+ pfm_arch_restore_pmcs(ctx, ctx->ctx_active_set);
+}
+
+void pfm_arch_mask_monitoring(struct pfm_context *ctx)
+{
+ mtspr(SPRN_MMCR0, MMCR0_FC);
+}
+
+void pfm_arch_unmask_monitoring(struct pfm_context *ctx)
+{
+ /*
+ * on ppc64 masking/unmasking uses start/stop
+ * mechanism
+ */
+ __pfm_arch_start(current, ctx, ctx->ctx_active_set);
+}
+
+/*
+ * invoked from arch/ppc64/kernel.entry.S
+ */
+void ppc64_pfm_handle_work(void)
+{
+ pfm_handle_work();
+}
+
+static void pfm_stop_one_pmu(void *data)
+{
+ mtspr(SPRN_MMCR0, MMCR0_FC);
+}
+
+/*
+ * called from pfm_register_pmu_config() after the new
+ * config has been validated and installed. The pfm_session_lock
+ * is held. Interrupts are not masked.
+ *
+ * The role of the function is, based on the PMU description, to
+ * put the PMU into a quiet state on each CPU. This function is only
+ * needed when there is no architected way to do this operation. In
+ * that case nothing can be done before a pmu description is registered.
+ */
+void pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg)
+{
+ on_each_cpu(pfm_stop_one_pmu, cfg, 1, 1);
+}
diff -urN linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/perfmon_power5.c linux-2.6.15-rc1-git6/arch/powerpc/perfmon/perfmon_power5.c
--- linux-2.6.15-rc1-git6.orig/arch/powerpc/perfmon/perfmon_power5.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.15-rc1-git6/arch/powerpc/perfmon/perfmon_power5.c 2005-11-18 05:48:12.000000000 -0800
@@ -0,0 +1,103 @@
+/*
+ * This file contains the POWER4 and decendent PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (c) 2005 David Gibson, IBM Corporation.
+ *
+ * Based on perfmon_p6.c:
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ */
+#include <linux/module.h>
+#include <linux/perfmon.h>
+
+MODULE_AUTHOR("David Gibson <dwg@au1.ibm.com>");
+MODULE_DESCRIPTION("POWER4 performance counters");
+MODULE_LICENSE("GPL");
+
+static struct pfm_reg_desc pfm_power5_pmc_desc[PFM_MAX_PMCS+1]={
+/* mmcr0 */ {PFM_REG_W, "MMCR0", MMCR0_FC, 0, {RDEP(0)|RDEP(1)|RDEP(2)|RDEP(3)|RDEP(4)|RDEP(5)|RDEP(6)}},
+/* mmcr1 */ {PFM_REG_W, "MMCR1", 0x0, 0, {RDEP(0)|RDEP(1)|RDEP(2)|RDEP(3)|RDEP(4)|RDEP(5)|RDEP(6)}},
+/* mmcra */ {PFM_REG_W, "MMCRA", 0x0, 0, {RDEP(0)|RDEP(1)|RDEP(2)|RDEP(3)|RDEP(4)|RDEP(5)|RDEP(6)}},
+ {PFM_REG_END,} /* end marker */
+};
+
+static struct pfm_reg_desc pfm_power5_pmd_desc[PFM_MAX_PMDS+1]={
+/* tb */ {PFM_REG_C, "TB" , 0x0, -1, {0}},
+/* pmd1 */ {PFM_REG_C, "PMC1", 0x0, 0, {0}},
+/* pmd2 */ {PFM_REG_C, "PMC2", 0x0, 0, {0}},
+/* pmd3 */ {PFM_REG_C, "PMC3", 0x0, 0, {0}},
+/* pmd4 */ {PFM_REG_C, "PMC4", 0x0, 0, {0}},
+/* pmd5 */ {PFM_REG_C, "PMC5", 0x0, 0, {0}},
+/* pmd6 */ {PFM_REG_C, "PMC6", 0x0, 0, {0}},
+ { PFM_REG_END, } /* end marker */
+};
+
+static int pfm_power5_pmc_check(struct pfm_context *ctx, struct pfm_event_set *set,
+ u16 cnum, u32 flags, u64 *val)
+{
+ u64 tmpval;
+ u64 tmp1, tmp2;
+ u64 rsvd_mask, dfl_value;
+
+ tmpval = *val;
+ rsvd_mask = pfm_power5_pmc_desc[cnum].reserved_mask;
+ dfl_value = pfm_power5_pmc_desc[cnum].default_value;
+
+ /* remove reserved areas from user value */
+ tmp1 = tmpval & rsvd_mask;
+
+ /* get reserved fields values */
+ tmp2 = dfl_value & ~rsvd_mask;
+
+ tmpval = tmp1 | tmp2;
+
+ *val = tmpval;
+
+ DPRINT(("pmc%u(%s): ival=0x%llx, rsvd_mask=0x%llx, def_value=0x%llx, "
+ "new_val=0x%llx\n",
+ cnum,
+ pfm_power5_pmc_desc[cnum].desc,
+ (unsigned long long)*val,
+ (unsigned long long)rsvd_mask,
+ (unsigned long long)dfl_value,
+ (unsigned long long)tmpval));
+
+ return 0;
+}
+
+static int pfm_power5_probe_pmu(void)
+{
+ unsigned long pvr = mfspr(SPRN_PVR);
+
+ if (PVR_VER(pvr) != PV_POWER5)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static struct pfm_pmu_config pfm_power5_pmu_conf = {
+ .pmu_name = "POWER5",
+ .counter_width = 31,
+ .pmd_desc = pfm_power5_pmd_desc,
+ .pmc_desc = pfm_power5_pmc_desc,
+ .pmc_write_check = pfm_power5_pmc_check,
+ .probe_pmu = pfm_power5_probe_pmu,
+ .version = "0.0"
+};
+
+static int __init pfm_power5_pmu_init_module(void)
+{
+ return pfm_register_pmu_config(&pfm_power5_pmu_conf);
+}
+
+static void __exit pfm_power5_pmu_cleanup_module(void)
+{
+ pfm_unregister_pmu_config(&pfm_power5_pmu_conf);
+}
+
+module_init(pfm_power5_pmu_init_module);
+module_exit(pfm_power5_pmu_cleanup_module);
diff -urN linux-2.6.15-rc1-git6.orig/include/asm-powerpc/perfmon.h linux-2.6.15-rc1-git6/include/asm-powerpc/perfmon.h
--- linux-2.6.15-rc1-git6.orig/include/asm-powerpc/perfmon.h 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.15-rc1-git6/include/asm-powerpc/perfmon.h 2005-11-18 05:48:12.000000000 -0800
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2005 David Gibson, IBM Corporation.
+ *
+ * Based on other versions:
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file contains ppc64 specific definitions for the perfmon
+ * interface.
+ *
+ * This file MUST never be included directly. Use linux/perfmon.h.
+ */
+#ifndef _ASM_PPC64_PERFMON_H_
+#define _ASM_PPC64_PERFMON_H_
+
+#ifdef __KERNEL__
+
+/*
+ * on som PMU models, the upper bits of a counter must be set in order
+ * for the overflow interrupt to happen. On overflow, the counter
+ * has wrapped around, and the upper bits are now cleared. This
+ * function set them back.
+ *
+ * The current version loses whatever is remaining in the counter,
+ * which is usually not zero but has a small count. In order not
+ * to loose this count, we do a read-modify-write to set the upper
+ * bits while preserving the low-order bits. This is slow but
+ * works.
+ */
+static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, unsigned int cnum)
+{
+}
+
+static inline void
+pfm_arch_resend_irq(void)
+{
+ /* nothing needed */
+}
+
+#define pfm_arch_serialize() /* nothing */
+
+static inline void
+pfm_arch_unfreeze_pmu(void)
+{
+}
+
+static inline u64
+pfm_arch_get_itc(void)
+{
+ return mftb();
+}
+
+static inline void
+pfm_arch_write_pmc(struct pfm_context *ctx, unsigned int cnum, u64 value)
+{
+ switch (cnum) {
+ case 0:
+ mtspr(SPRN_MMCR0, value);
+ break;
+ case 1:
+ mtspr(SPRN_MMCR1, value);
+ break;
+ case 2:
+ mtspr(SPRN_MMCRA, value);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline void
+pfm_arch_write_pmd(struct pfm_context *ctx, unsigned int cnum, u64 value)
+{
+ switch (cnum) {
+ case 1:
+ mtspr(SPRN_PMC1, value);
+ break;
+ case 2:
+ mtspr(SPRN_PMC2, value);
+ break;
+ case 3:
+ mtspr(SPRN_PMC3, value);
+ break;
+ case 4:
+ mtspr(SPRN_PMC4, value);
+ break;
+ case 5:
+ mtspr(SPRN_PMC5, value);
+ break;
+ case 6:
+ mtspr(SPRN_PMC6, value);
+ break;
+ case 7:
+ mtspr(SPRN_PMC7, value);
+ break;
+ case 8:
+ mtspr(SPRN_PMC8, value);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline u64
+pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum)
+{
+ switch (cnum) {
+ case 0:
+ return mftb();
+ break;
+ case 1:
+ return mfspr(SPRN_PMC1);
+ break;
+ case 2:
+ return mfspr(SPRN_PMC2);
+ break;
+ case 3:
+ return mfspr(SPRN_PMC3);
+ break;
+ case 4:
+ return mfspr(SPRN_PMC4);
+ break;
+ case 5:
+ return mfspr(SPRN_PMC5);
+ break;
+ case 6:
+ return mfspr(SPRN_PMC6);
+ break;
+ case 7:
+ return mfspr(SPRN_PMC7);
+ break;
+ case 8:
+ return mfspr(SPRN_PMC8);
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline u64
+pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum)
+{
+ switch (cnum) {
+ case 0:
+ return mfspr(SPRN_MMCR0);
+ break;
+ case 1:
+ return mfspr(SPRN_MMCR1);
+ break;
+ case 2:
+ return mfspr(SPRN_MMCRA);
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/*
+ * At certain points, perfmon needs to know if monitoring has been
+ * explicitely started/stopped by user via pfm_start/pfm_stop. The
+ * information is tracked in ctx_fl_started. However on certain
+ * architectures, it may be possible to start/stop directly from
+ * user level with a single assembly instruction bypassing
+ * the kernel. This function must be used to determine by
+ * an arch-specific mean if monitoring is actually started/stopped.
+ * If there is no other way but to go through pfm_start/pfm_stop
+ * then this function can simply return 0
+ */
+static inline int pfm_arch_is_active(struct pfm_context *ctx)
+{
+ return 0;
+}
+
+extern void pfm_arch_init_percpu(void);
+extern int pfm_arch_is_monitoring_active(struct pfm_context *ctx);
+extern void pfm_arch_ctxswout(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set);
+extern void pfm_arch_ctxswin(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set);
+extern void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set);
+extern void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx,
+ struct pfm_event_set *set);
+extern void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set);
+extern void pfm_arch_save_pmds(struct pfm_context *ctx, struct pfm_event_set *set);
+extern void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set);
+extern int pfm_arch_get_ovfl_pmds(struct pfm_context *ctx,
+ struct pfm_event_set *set);
+extern void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx);
+extern void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx);
+extern int pfm_arch_initialize(void);
+extern void pfm_arch_mask_monitoring(struct pfm_context *ctx);
+extern void pfm_arch_unmask_monitoring(struct pfm_context *ctx);
+extern void pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg);
+
+/*
+ * called from pfm_register_pmu_config() after the new
+ * config has been validated and installed. The pfs_lock is held
+ * is held.
+ *
+ * Must sanity check the arch-specific config information
+ *
+ * return:
+ * < 0 : if error
+ * 0 : if success
+ */
+static inline int pfm_arch_pmu_config_check(struct pfm_pmu_config *cfg)
+{
+ return 0;
+}
+
+//static inline void pfm_arch_context_initialize(struct pfm_context *ctx, u32 ctx_flags);
+#define pfm_arch_context_initialize(ctx, ctx_flags) /* nothing */
+
+extern int pfm_arch_load_context(struct pfm_context *ctx, struct task_struct *task);
+extern void pfm_arch_unload_context(struct pfm_context *ctx, struct task_struct *task);
+
+static inline int
+pfm_arch_reserve_session(struct pfm_context *ctx, unsigned int cpu)
+{
+ return 0;
+}
+
+//static inline void pfm_arch_unreserve_session(struct pfm_context *ctx, unsigned int cpu)
+#define pfm_arch_unreserve_session(ctx, cpu) /* nothing */
+
+
+/*
+ * function called from pfm_setfl_sane(). Context is locked
+ * and interrupts are masked.
+ * The value of flags is the value of ctx_flags as passed by
+ * user.
+ *
+ * function must check arch-specific set flags.
+ * Return:
+ * 1 when flags are valid
+ * 0 on error
+ */
+static inline int
+pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags)
+{
+ return 0;
+}
+
+//static inline void pfm_arch_show_session(struct seq_file *m);
+#define pfm_arch_show_session(m) /* nothing */
+
+struct pfm_arch_context {
+ /* empty */
+};
+
+#define PFM_ARCH_CTX_SIZE sizeof(struct pfm_arch_context)
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_PPC64_PERFMON_H_ */
diff -urN linux-2.6.15-rc1-git6.orig/include/asm-powerpc/processor.h linux-2.6.15-rc1-git6/include/asm-powerpc/processor.h
--- linux-2.6.15-rc1-git6.orig/include/asm-powerpc/processor.h 2005-11-18 05:16:51.000000000 -0800
+++ linux-2.6.15-rc1-git6/include/asm-powerpc/processor.h 2005-11-18 05:48:12.000000000 -0800
@@ -194,6 +194,7 @@
unsigned long spefscr; /* SPE & eFP status */
int used_spe; /* set if process has used spe */
#endif /* CONFIG_SPE */
+ void *pfm_context;
};
#define ARCH_MIN_TASKALIGN 16
diff -urN linux-2.6.15-rc1-git6.orig/include/asm-powerpc/unistd.h linux-2.6.15-rc1-git6/include/asm-powerpc/unistd.h
--- linux-2.6.15-rc1-git6.orig/include/asm-powerpc/unistd.h 2005-11-18 05:16:51.000000000 -0800
+++ linux-2.6.15-rc1-git6/include/asm-powerpc/unistd.h 2005-11-18 05:48:12.000000000 -0800
@@ -297,6 +297,19 @@
#define __NR_inotify_add_watch 276
#define __NR_inotify_rm_watch 277
+#define __NR_pfm_create_context 278
+#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1)
+#define __NR_pfm_write_pmds (__NR_pfm_create_context+2)
+#define __NR_pfm_read_pmds (__NR_pfm_create_context+3)
+#define __NR_pfm_load_context (__NR_pfm_create_context+4)
+#define __NR_pfm_start (__NR_pfm_create_context+5)
+#define __NR_pfm_stop (__NR_pfm_create_context+6)
+#define __NR_pfm_restart (__NR_pfm_create_context+7)
+#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8)
+#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9)
+#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10)
+#define __NR_pfm_unload_context (__NR_pfm_create_context+11)
+
#define __NR_syscalls 278
#ifdef __KERNEL__
next prev parent reply other threads:[~2005-11-23 14:58 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-11-18 17:00 2.6.15-rc1-git6 perfmon new code base package available Stephane Eranian
2005-11-18 17:00 ` Stephane Eranian
[not found] ` <20051123145308.GB17228@frankl.hpl.hp.com>
2005-11-23 14:55 ` [PATCH 3/5] i386 perfmon2 code for review Stephane Eranian
2005-11-23 14:56 ` [PATCH 4/5] x86-64 " Stephane Eranian
2005-11-23 14:57 ` Stephane Eranian [this message]
2005-11-23 15:15 ` [PATCH 3/5] i386 " Dave Hansen
2005-11-23 21:13 ` [PATCH 1/5] common " Stephane Eranian
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20051123145754.GF17228@frankl.hpl.hp.com \
--to=eranian@hpl.hp.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.