diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-11-11 18:00:33 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-11-11 18:00:33 +1100 |
commit | 6bfea1858872c1e57d94d686e3144bfa10ca48cb (patch) | |
tree | cfe7ad66c1f9a14f9d419c3ebf3100264b0044d4 /arch/x86/include/asm | |
parent | bc6435afdc6a1e0c5236a4a031f372bc1c62341d (diff) | |
parent | 4872c7055867a9b583c76cd7744030dd515a5f35 (diff) |
Merge commit 'perfmon3/master'
Diffstat (limited to 'arch/x86/include/asm')
-rw-r--r-- | arch/x86/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/irq_vectors.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/mach-default/entry_arch.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/perfmon.h | 34 | ||||
-rw-r--r-- | arch/x86/include/asm/perfmon_kern.h | 438 | ||||
-rw-r--r-- | arch/x86/include/asm/thread_info.h | 8 | ||||
-rw-r--r-- | arch/x86/include/asm/unistd_32.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/unistd_64.h | 11 |
8 files changed, 503 insertions, 3 deletions
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild index 4a8e80cdcfa5..15d495f73485 100644 --- a/arch/x86/include/asm/Kbuild +++ b/arch/x86/include/asm/Kbuild @@ -10,6 +10,7 @@ header-y += ptrace-abi.h header-y += sigcontext32.h header-y += ucontext.h header-y += processor-flags.h +header-y += perfmon.h unifdef-y += e820.h unifdef-y += ist.h diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 0005adb0f941..0ba6dd3aa24e 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -87,6 +87,11 @@ #define LOCAL_TIMER_VECTOR 0xef /* + * Perfmon PMU interrupt vector + */ +#define LOCAL_PERFMON_VECTOR 0xee + +/* * First APIC vector available to drivers: (vectors 0x30-0xee) we * start at 0x31(0x41) to spread out vectors evenly between priority * levels. (0x80 is the syscall vector) diff --git a/arch/x86/include/asm/mach-default/entry_arch.h b/arch/x86/include/asm/mach-default/entry_arch.h index 6b1add8e31dd..e940722dc1f0 100644 --- a/arch/x86/include/asm/mach-default/entry_arch.h +++ b/arch/x86/include/asm/mach-default/entry_arch.h @@ -33,4 +33,8 @@ BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) #endif +#ifdef CONFIG_PERFMON +BUILD_INTERRUPT(pmu_interrupt,LOCAL_PERFMON_VECTOR) +#endif + #endif diff --git a/arch/x86/include/asm/perfmon.h b/arch/x86/include/asm/perfmon.h new file mode 100644 index 000000000000..906f4b24cf0c --- /dev/null +++ b/arch/x86/include/asm/perfmon.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2007 Hewlett-Packard Development Company, L.P. + * Contributed by Stephane Eranian <eranian@hpl.hp.com> + * + * This file contains i386/x86_64 specific definitions for the perfmon + * interface. + * + * This file MUST never be included directly. Use linux/perfmon.h. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +#ifndef _ASM_X86_PERFMON__H_ +#define _ASM_X86_PERFMON__H_ + +/* + * arch-specific user visible interface definitions + */ + +#define PFM_ARCH_MAX_PMCS (256+64) /* 256 HW 64 SW */ +#define PFM_ARCH_MAX_PMDS (256+64) /* 256 HW 64 SW */ + +#endif /* _ASM_X86_PERFMON_H_ */ diff --git a/arch/x86/include/asm/perfmon_kern.h b/arch/x86/include/asm/perfmon_kern.h new file mode 100644 index 000000000000..7cadbb894e83 --- /dev/null +++ b/arch/x86/include/asm/perfmon_kern.h @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. + * Contributed by Stephane Eranian <eranian@hpl.hp.com> + * + * Copyright (c) 2007 Advanced Micro Devices, Inc. + * Contributed by Robert Richter <robert.richter@amd.com> + * + * This file contains X86 Processor Family specific definitions + * for the perfmon interface. This covers P6, Pentium M, P4/Xeon + * (32-bit and 64-bit, i.e., EM64T) and AMD X86-64. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +#ifndef _ASM_X86_PERFMON_KERN_H_ +#define _ASM_X86_PERFMON_KERN_H_ + +#ifdef CONFIG_PERFMON +#include <linux/unistd.h> +#ifdef CONFIG_4KSTACKS +#define PFM_ARCH_STK_ARG 8 +#else +#define PFM_ARCH_STK_ARG 16 +#endif + +struct pfm_arch_pmu_info { + u32 flags; /* PMU feature flags */ + /* + * mandatory model-specific callbacks + */ + int (*stop_save)(struct pfm_context *ctx, struct pfm_event_set *set); + int (*has_ovfls)(struct pfm_context *ctx); + void (*quiesce)(void); + + /* + * optional model-specific callbacks + */ + void (*acquire_pmu_percpu)(void); + void (*release_pmu_percpu)(void); + int (*load_context)(struct pfm_context *ctx); + void (*unload_context)(struct pfm_context *ctx); +}; + +/* + * PMU feature flags + */ +#define PFM_X86_FL_NO_SHARING 0x02 /* no sharing with other subsystems */ +#define PFM_X86_FL_SHARING 0x04 /* PMU is being shared */ + +struct pfm_x86_ctx_flags { + unsigned int insecure:1; /* rdpmc per-thread self-monitoring */ + unsigned int reserved:31; /* for future use */ +}; + +struct pfm_arch_context { + u64 saved_real_iip; /* instr pointer of last NMI intr */ + struct pfm_x86_ctx_flags flags; /* flags */ + int saved_started; +}; + +/* + * functions implemented as inline on x86 + */ + +/** + * pfm_arch_write_pmc - write a single PMC register + * @ctx: context to work on + * @cnum: PMC index + * @value: PMC 64-bit value + * + * in certain situations, ctx may be NULL + */ +static inline void pfm_arch_write_pmc(struct pfm_context *ctx, + unsigned int cnum, u64 value) +{ + /* + * we only write to the actual register when monitoring is + * active (pfm_start was issued) + */ + if (ctx && ctx->flags.started == 0) + return; + + PFM_DBG_ovfl("pfm_arch_write_pmc(0x%lx, 0x%Lx)", + pfm_pmu_conf->pmc_desc[cnum].hw_addr, + (unsigned long long) value); + + wrmsrl(pfm_pmu_conf->pmc_desc[cnum].hw_addr, value); +} + +/** + * pfm_arch_write_pmd - write a single PMD register + * @ctx: context to work on + * @cnum: PMD index + * @value: PMD 64-bit value + */ +static inline void pfm_arch_write_pmd(struct pfm_context *ctx, + unsigned int cnum, u64 value) +{ + /* + * to make sure the counter overflows, we set the + * upper bits. we also clear any other unimplemented + * bits as this may cause crash on some processors. + */ + if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64) + value = (value | ~pfm_pmu_conf->ovfl_mask) + & ~pfm_pmu_conf->pmd_desc[cnum].rsvd_msk; + + PFM_DBG_ovfl("pfm_arch_write_pmd(0x%lx, 0x%Lx)", + pfm_pmu_conf->pmd_desc[cnum].hw_addr, + (unsigned long long) value); + + wrmsrl(pfm_pmu_conf->pmd_desc[cnum].hw_addr, value); +} + +/** + * pfm_arch_read_pmd - read a single PMD register + * @ctx: context to work on + * @cnum: PMD index + * + * return value is register 64-bit value + */ +static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum) +{ + u64 tmp; + + rdmsrl(pfm_pmu_conf->pmd_desc[cnum].hw_addr, tmp); + + PFM_DBG_ovfl("pfm_arch_read_pmd(0x%lx) = 0x%Lx", + pfm_pmu_conf->pmd_desc[cnum].hw_addr, + (unsigned long long) tmp); + return tmp; +} + +/** + * pfm_arch_read_pmc - read a single PMC register + * @ctx: context to work on + * @cnum: PMC index + * + * return value is register 64-bit value + */ +static inline u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum) +{ + u64 tmp; + + rdmsrl(pfm_pmu_conf->pmc_desc[cnum].hw_addr, tmp); + + PFM_DBG_ovfl("pfm_arch_read_pmc(0x%lx) = 0x%016Lx", + pfm_pmu_conf->pmc_desc[cnum].hw_addr, + (unsigned long long) tmp); + return tmp; +} + +/** + * pfm_arch_is_active - return non-zero is monitoring has been started + * @ctx: context to check + * + * At certain points, perfmon needs to know if monitoring has been + * explicitly started. + * + * On x86, there is not other way but to use pfm_start/pfm_stop + * to activate monitoring, thus we can simply check flags.started + */ +static inline int pfm_arch_is_active(struct pfm_context *ctx) +{ + return ctx->flags.started; +} + + +/** + * pfm_arch_unload_context - detach context from thread or CPU + * @ctx: context to detach + * + * in system-wide ctx->task is NULL, otherwise it points to the + * attached thread + */ +static inline void pfm_arch_unload_context(struct pfm_context *ctx) +{ + struct pfm_arch_pmu_info *pmu_info; + struct pfm_arch_context *ctx_arch; + + ctx_arch = pfm_ctx_arch(ctx); + pmu_info = pfm_pmu_info(); + + if (ctx_arch->flags.insecure) { + PFM_DBG("clear cr4.pce"); + clear_in_cr4(X86_CR4_PCE); + } + + if (pmu_info->unload_context) + pmu_info->unload_context(ctx); +} + +/** + * pfm_arch_load_context - attach context to thread or CPU + * @ctx: context to attach + */ +static inline int pfm_arch_load_context(struct pfm_context *ctx) +{ + struct pfm_arch_pmu_info *pmu_info; + struct pfm_arch_context *ctx_arch; + int ret = 0; + + ctx_arch = pfm_ctx_arch(ctx); + pmu_info = pfm_pmu_info(); + + /* + * RDPMC authorized in system-wide and + * per-thread self-monitoring. + * + * RDPMC only gives access to counts. + * + * The context-switch routine code does not restore + * all the PMD registers (optimization), thus there + * is a possible leak of counts there in per-thread + * mode. + */ + if (ctx->task == current) { + PFM_DBG("set cr4.pce"); + set_in_cr4(X86_CR4_PCE); + ctx_arch->flags.insecure = 1; + } + + if (pmu_info->load_context) + ret = pmu_info->load_context(ctx); + + return ret; +} + +void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); +void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx); +void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx); + +/** + * pfm_arch_intr_freeze_pmu - stop monitoring when handling PMU interrupt + * @ctx: current context + * @set: current event set + * + * called from __pfm_interrupt_handler(). + * ctx is not NULL. ctx is locked. interrupts are masked + * + * The following actions must take place: + * - stop all monitoring to ensure handler has consistent view. + * - collect overflowed PMDs bitmask into povfls_pmds and + * npend_ovfls. If no interrupt detected then npend_ovfls + * must be set to zero. + */ +static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, + struct pfm_event_set *set) +{ + struct pfm_arch_context *ctx_arch; + ctx_arch = pfm_ctx_arch(ctx); + /* + * on X86, freezing is equivalent to stopping + */ + pfm_arch_stop(current, ctx); + + /* + * we mark monitoring as stopped to avoid + * certain side effects especially in + * pfm_arch_restore_pmcs() + */ + ctx_arch->saved_started = ctx->flags.started; + ctx->flags.started = 0; +} + +/** + * pfm_arch_intr_unfreeze_pmu - conditionally reactive monitoring + * @ctx: current context + * + * current context may be not when dealing when spurious interrupts + * + * Must re-activate monitoring if context is not MASKED. + * interrupts are masked. + */ +static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx) +{ + struct pfm_arch_context *ctx_arch; + + if (ctx == NULL) + return; + + ctx_arch = pfm_ctx_arch(ctx); + + PFM_DBG_ovfl("state=%d", ctx->state); + + /* + * restore flags.started which is cleared in + * pfm_arch_intr_freeze_pmu() + */ + ctx->flags.started = ctx_arch->saved_started; + + pfm_arch_restore_pmcs(ctx, ctx->active_set); +} + +/** + * pfm_arch_ovfl_reset_pmd - reset pmd on overflow + * @ctx: current context + * @cnum: PMD index + * + * On some CPUs, 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 cleared. This function may be used to set them back. + * + * For x86, the current version loses whatever is remaining in the counter, + * which is usually 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) +{ + u64 val; + val = pfm_arch_read_pmd(ctx, cnum); + pfm_arch_write_pmd(ctx, cnum, val); +} + +/** + * pfm_arch_context_create - create context + * @ctx: newly created context + * @flags: context flags as passed by user + * + * called from __pfm_create_context() + */ +static inline int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags) +{ + return 0; +} + +/** + * pfm_arch_context_free - free context + * @ctx: context to free + */ +static inline void pfm_arch_context_free(struct pfm_context *ctx) +{} + +/* + * functions implemented in arch/x86/perfmon/perfmon.c + */ +int pfm_arch_init(void); +void pfm_arch_resend_irq(struct pfm_context *ctx); + +int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx); +void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx); + +void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set); +int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg); +void pfm_arch_pmu_config_remove(void); +char *pfm_arch_get_pmu_module_name(void); +int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds); +void pfm_arch_pmu_release(void); + +static inline void pfm_arch_serialize(void) +{} + +static inline void pfm_arch_arm_handle_work(struct task_struct *task) +{} + +static inline void pfm_arch_disarm_handle_work(struct task_struct *task) +{} + +#define PFM_ARCH_CTX_SIZE (sizeof(struct pfm_arch_context)) +/* + * x86 does not need extra alignment requirements for the sampling buffer + */ +#define PFM_ARCH_SMPL_ALIGN_SIZE 0 + +asmlinkage void pmu_interrupt(void); + +static inline void pfm_arch_bv_copy(u64 *a, u64 *b, int nbits) +{ + bitmap_copy((unsigned long *)a, + (unsigned long *)b, + nbits); +} + +static inline void pfm_arch_bv_or(u64 *a, u64 *b, u64 *c, int nbits) +{ + bitmap_or((unsigned long *)a, + (unsigned long *)b, + (unsigned long *)c, + nbits); +} + +static inline void pfm_arch_bv_and(u64 *a, u64 *b, u64 *c, int nbits) +{ + bitmap_and((unsigned long *)a, + (unsigned long *)b, + (unsigned long *)c, + nbits); +} + + +static inline void pfm_arch_bv_zero(u64 *a, int nbits) +{ + bitmap_zero((unsigned long *)a, nbits); +} + +static inline int pfm_arch_bv_weight(u64 *a, int nbits) +{ + return bitmap_weight((unsigned long *)a, nbits); +} + +static inline void pfm_arch_bv_set_bit(int b, u64 *a) +{ + __set_bit(b, (unsigned long *)a); +} + +static inline void pfm_arch_bv_clear_bit(int b, u64 *a) +{ + __clear_bit(b, (unsigned long *)a); +} + +static inline int pfm_arch_bv_test_bit(int b, u64 *a) +{ + return test_bit(b, (unsigned long *)a); +} + +static inline unsigned long pfm_arch_bv_find_next_bit(const u64 *addr, + unsigned long size, + unsigned long offset) +{ + return find_next_bit((unsigned long *)addr, + size, + offset); +} +#endif /* CONFIG_PEFMON */ + +#endif /* _ASM_X86_PERFMON_KERN_H_ */ diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index e44d379faad2..0ddd534bef44 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -79,6 +79,7 @@ struct thread_info { #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ +#define TIF_PERFMON_WORK 9 /* work for pfm_handle_work() */ #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ #define TIF_NOTSC 16 /* TSC is not accessible in userland */ #define TIF_IA32 17 /* 32bit process */ @@ -92,6 +93,7 @@ struct thread_info { #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ #define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ +#define TIF_PERFMON_CTXSW 28 /* perfmon needs ctxsw calls */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -114,6 +116,8 @@ struct thread_info { #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) #define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS) +#define _TIF_PERFMON_WORK (1<<TIF_PERFMON_WORK) +#define _TIF_PERFMON_CTXSW (1<<TIF_PERFMON_CTXSW) /* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ @@ -135,12 +139,12 @@ struct thread_info { /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ - (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME) + (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_PERFMON_WORK) /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \ - _TIF_NOTSC) + _TIF_NOTSC|_TIF_PERFMON_CTXSW) #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h index f2bba78430a4..06908451002f 100644 --- a/arch/x86/include/asm/unistd_32.h +++ b/arch/x86/include/asm/unistd_32.h @@ -338,6 +338,11 @@ #define __NR_dup3 330 #define __NR_pipe2 331 #define __NR_inotify_init1 332 +#define __NR_pfm_create 333 +#define __NR_pfm_write (__NR_pfm_create+1) +#define __NR_pfm_read (__NR_pfm_create+2) +#define __NR_pfm_attach (__NR_pfm_create+3) +#define __NR_pfm_set_state (__NR_pfm_create+4) #ifdef __KERNEL__ diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h index 834b2c1d89fb..a42bb5eb9edb 100644 --- a/arch/x86/include/asm/unistd_64.h +++ b/arch/x86/include/asm/unistd_64.h @@ -653,7 +653,16 @@ __SYSCALL(__NR_dup3, sys_dup3) __SYSCALL(__NR_pipe2, sys_pipe2) #define __NR_inotify_init1 294 __SYSCALL(__NR_inotify_init1, sys_inotify_init1) - +#define __NR_pfm_create 295 +__SYSCALL(__NR_pfm_create, sys_pfm_create) +#define __NR_pfm_write (__NR_pfm_create+1) +__SYSCALL(__NR_pfm_write, sys_pfm_write) +#define __NR_pfm_read (__NR_pfm_create+2) + __SYSCALL(__NR_pfm_read, sys_pfm_read) +#define __NR_pfm_attach (__NR_pfm_create+3) +__SYSCALL(__NR_pfm_attach, sys_pfm_attach) +#define __NR_pfm_set_state (__NR_pfm_create+4) +__SYSCALL(__NR_pfm_set_state, sys_pfm_set_state) #ifndef __NO_STUBS #define __ARCH_WANT_OLD_READDIR |