|
Packit |
577717 |
/* $Id: x86.c,v 1.127.2.70 2010/11/07 19:46:06 mikpe Exp $
|
|
Packit |
577717 |
* x86/x86_64 performance-monitoring counters driver.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (C) 1999-2010 Mikael Pettersson
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <linux/version.h>
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
|
Packit |
577717 |
#include <linux/config.h>
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
#define __NO_VERSION__
|
|
Packit |
577717 |
#include <linux/module.h>
|
|
Packit |
577717 |
#include <linux/init.h>
|
|
Packit |
577717 |
#include <linux/sched.h>
|
|
Packit |
577717 |
#include <linux/fs.h>
|
|
Packit |
577717 |
#include <linux/perfctr.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include <asm/msr.h>
|
|
Packit |
577717 |
#undef MSR_P6_PERFCTR0
|
|
Packit |
577717 |
#undef MSR_P6_EVNTSEL0
|
|
Packit |
577717 |
#undef MSR_K7_PERFCTR0
|
|
Packit |
577717 |
#undef MSR_K7_EVNTSEL0
|
|
Packit |
577717 |
#undef MSR_CORE_PERF_FIXED_CTR0
|
|
Packit |
577717 |
#undef MSR_CORE_PERF_FIXED_CTR_CTRL
|
|
Packit |
577717 |
#undef MSR_CORE_PERF_GLOBAL_CTRL
|
|
Packit |
577717 |
#undef MSR_IA32_MISC_ENABLE
|
|
Packit |
577717 |
#undef MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL
|
|
Packit |
577717 |
#undef MSR_IA32_DEBUGCTLMSR
|
|
Packit |
577717 |
#include <asm/fixmap.h>
|
|
Packit |
577717 |
#include <asm/apic.h>
|
|
Packit |
577717 |
struct hw_interrupt_type;
|
|
Packit |
577717 |
#include <asm/hw_irq.h>
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) && defined(CONFIG_X86_LOCAL_APIC)
|
|
Packit |
577717 |
#include <asm/nmi.h>
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "compat.h"
|
|
Packit |
577717 |
#include "x86_compat.h"
|
|
Packit |
577717 |
#include "x86_tests.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Support for lazy evntsel and perfctr MSR updates. */
|
|
Packit |
577717 |
struct per_cpu_cache { /* roughly a subset of perfctr_cpu_state */
|
|
Packit |
577717 |
union {
|
|
Packit |
577717 |
unsigned int p5_cesr;
|
|
Packit |
577717 |
unsigned int id; /* cache owner id */
|
|
Packit |
577717 |
} k1;
|
|
Packit |
577717 |
struct {
|
|
Packit |
577717 |
/* NOTE: these caches have physical indices, not virtual */
|
|
Packit |
577717 |
unsigned int evntsel[18];
|
|
Packit |
577717 |
union {
|
|
Packit |
577717 |
unsigned int escr[0x3E2-0x3A0];
|
|
Packit |
577717 |
unsigned int evntsel_high[18];
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
unsigned int pebs_enable;
|
|
Packit |
577717 |
unsigned int pebs_matrix_vert;
|
|
Packit |
577717 |
} control;
|
|
Packit |
577717 |
unsigned int core2_fixed_ctr_ctrl;
|
|
Packit |
577717 |
unsigned int nhlm_offcore_rsp[2];
|
|
Packit |
577717 |
} ____cacheline_aligned;
|
|
Packit |
577717 |
static struct per_cpu_cache per_cpu_cache[NR_CPUS] __cacheline_aligned;
|
|
Packit |
577717 |
#define __get_cpu_cache(cpu) (&per_cpu_cache[cpu])
|
|
Packit |
577717 |
#define get_cpu_cache() __get_cpu_cache(smp_processor_id())
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Structure for counter snapshots, as 32-bit values. */
|
|
Packit |
577717 |
struct perfctr_low_ctrs {
|
|
Packit |
577717 |
unsigned int tsc;
|
|
Packit |
577717 |
unsigned int pmc[18];
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Structures for describing the set of PMU MSRs. */
|
|
Packit |
577717 |
struct perfctr_msr_range {
|
|
Packit |
577717 |
unsigned int first_msr;
|
|
Packit |
577717 |
unsigned int nr_msrs;
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
struct perfctr_pmu_msrs {
|
|
Packit |
577717 |
const struct perfctr_msr_range *perfctrs; /* for {reserve,release}_perfctr_nmi() */
|
|
Packit |
577717 |
const struct perfctr_msr_range *evntsels; /* for {reserve,release}_evntsel_nmi() */
|
|
Packit |
577717 |
const struct perfctr_msr_range *extras;
|
|
Packit |
577717 |
void (*clear_counters)(int init);
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel P5, Cyrix 6x86MX/MII/III, Centaur WinChip C6/2/3 */
|
|
Packit |
577717 |
#define MSR_P5_CESR 0x11
|
|
Packit |
577717 |
#define MSR_P5_CTR0 0x12 /* .. 0x13 */
|
|
Packit |
577717 |
#define P5_CESR_CPL 0x00C0
|
|
Packit |
577717 |
#define P5_CESR_RESERVED (~0x01FF)
|
|
Packit |
577717 |
#define MII_CESR_RESERVED (~0x05FF)
|
|
Packit |
577717 |
#define C6_CESR_RESERVED (~0x00FF)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel P6, VIA C3 */
|
|
Packit |
577717 |
#define MSR_P6_PERFCTR0 0xC1 /* .. 0xC4 */
|
|
Packit |
577717 |
#define MSR_P6_EVNTSEL0 0x186 /* .. 0x189 */
|
|
Packit |
577717 |
#define P6_EVNTSEL_ENABLE 0x00400000
|
|
Packit |
577717 |
#define P6_EVNTSEL_INT 0x00100000
|
|
Packit |
577717 |
#define P6_EVNTSEL_CPL 0x00030000
|
|
Packit |
577717 |
#define P6_EVNTSEL_RESERVED 0x00280000
|
|
Packit |
577717 |
#define VC3_EVNTSEL1_RESERVED (~0x1FF)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel Core */
|
|
Packit |
577717 |
#define MSR_IA32_DEBUGCTLMSR 0x000001D9
|
|
Packit |
577717 |
#define MSR_IA32_DEBUGCTLMSR_FREEZE_PERFMON_ON_PMI (1<<12)
|
|
Packit |
577717 |
#define MSR_CORE_PERF_FIXED_CTR0 0x309 /* .. 0x30B */
|
|
Packit |
577717 |
#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x38D
|
|
Packit |
577717 |
#define MSR_CORE_PERF_FIXED_CTR_CTRL_PMIANY 0x00000888
|
|
Packit |
577717 |
#define MSR_CORE_PERF_GLOBAL_CTRL 0x38F
|
|
Packit |
577717 |
#define CORE2_PMC_FIXED_FLAG (1<<30)
|
|
Packit |
577717 |
#define CORE2_PMC_FIXED_MASK 0x3
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel Nehalem */
|
|
Packit |
577717 |
#define MSR_OFFCORE_RSP0 0x1A6 /* Westmere has another at 0x1A7 */
|
|
Packit |
577717 |
#define OFFCORE_RSP_RESERVED (~0xF7FF)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* AMD K7 */
|
|
Packit |
577717 |
#define MSR_K7_EVNTSEL0 0xC0010000 /* .. 0xC0010003 */
|
|
Packit |
577717 |
#define MSR_K7_PERFCTR0 0xC0010004 /* .. 0xC0010007 */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* AMD K8 */
|
|
Packit |
577717 |
#define IS_K8_NB_EVENT(EVNTSEL) ((((EVNTSEL) >> 5) & 0x7) == 0x7)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* AMD Family 10h */
|
|
Packit |
577717 |
#define FAM10H_EVNTSEL_HIGH_RESERVED (~0x30F)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel P4, Intel Pentium M, Intel Core */
|
|
Packit |
577717 |
#define MSR_IA32_MISC_ENABLE 0x1A0
|
|
Packit |
577717 |
#define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7) /* read-only status bit */
|
|
Packit |
577717 |
#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1<<12) /* read-only status bit */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel P4 */
|
|
Packit |
577717 |
#define MSR_P4_PERFCTR0 0x300 /* .. 0x311 */
|
|
Packit |
577717 |
#define MSR_P4_CCCR0 0x360 /* .. 0x371 */
|
|
Packit |
577717 |
#define MSR_P4_ESCR0 0x3A0 /* .. 0x3E1, with some gaps */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define MSR_P4_PEBS_ENABLE 0x3F1
|
|
Packit |
577717 |
#define P4_PE_REPLAY_TAG_BITS 0x00000607
|
|
Packit |
577717 |
#define P4_PE_UOP_TAG 0x01000000
|
|
Packit |
577717 |
#define P4_PE_RESERVED 0xFEFFF9F8 /* only allow ReplayTagging */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define MSR_P4_PEBS_MATRIX_VERT 0x3F2
|
|
Packit |
577717 |
#define P4_PMV_REPLAY_TAG_BITS 0x00000003
|
|
Packit |
577717 |
#define P4_PMV_RESERVED 0xFFFFFFFC
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define P4_CCCR_OVF 0x80000000
|
|
Packit |
577717 |
#define P4_CCCR_CASCADE 0x40000000
|
|
Packit |
577717 |
#define P4_CCCR_OVF_PMI_T1 0x08000000
|
|
Packit |
577717 |
#define P4_CCCR_OVF_PMI_T0 0x04000000
|
|
Packit |
577717 |
#define P4_CCCR_FORCE_OVF 0x02000000
|
|
Packit |
577717 |
#define P4_CCCR_ACTIVE_THREAD 0x00030000
|
|
Packit |
577717 |
#define P4_CCCR_ENABLE 0x00001000
|
|
Packit |
577717 |
#define P4_CCCR_ESCR_SELECT(X) (((X) >> 13) & 0x7)
|
|
Packit |
577717 |
#define P4_CCCR_EXTENDED_CASCADE 0x00000800
|
|
Packit |
577717 |
#define P4_CCCR_RESERVED (0x300007FF|P4_CCCR_OVF|P4_CCCR_OVF_PMI_T1)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define P4_ESCR_CPL_T1 0x00000003
|
|
Packit |
577717 |
#define P4_ESCR_CPL_T0 0x0000000C
|
|
Packit |
577717 |
#define P4_ESCR_TAG_ENABLE 0x00000010
|
|
Packit |
577717 |
#define P4_ESCR_RESERVED (0x80000000)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define P4_FAST_RDPMC 0x80000000
|
|
Packit |
577717 |
#define P4_MASK_FAST_RDPMC 0x0000001F /* we only need low 5 bits */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define rdmsr_low(msr,low) \
|
|
Packit |
577717 |
__asm__ __volatile__("rdmsr" : "=a"(low) : "c"(msr) : "edx")
|
|
Packit |
577717 |
#define rdpmc_low(ctr,low) \
|
|
Packit |
577717 |
__asm__ __volatile__("rdpmc" : "=a"(low) : "c"(ctr) : "edx")
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void clear_msr_range(unsigned int base, unsigned int n)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i = 0; i < n; ++i)
|
|
Packit |
577717 |
wrmsr(base+i, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void set_in_cr4_local(unsigned int mask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
write_cr4(read_cr4() | mask);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void clear_in_cr4_local(unsigned int mask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
write_cr4(read_cr4() & ~mask);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned int new_id(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static DEFINE_SPINLOCK(lock);
|
|
Packit |
577717 |
static unsigned int counter;
|
|
Packit |
577717 |
int id;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
spin_lock(&lock);
|
|
Packit |
577717 |
id = ++counter;
|
|
Packit |
577717 |
spin_unlock(&lock);
|
|
Packit |
577717 |
return id;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if defined(CONFIG_X86_LOCAL_APIC)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_cpu_mask_interrupts(const struct per_cpu_cache *cache)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
__perfctr_cpu_mask_interrupts();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_cpu_unmask_interrupts(const struct per_cpu_cache *cache)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
__perfctr_cpu_unmask_interrupts();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#else /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
#define perfctr_cstatus_has_ictrs(cstatus) 0
|
|
Packit |
577717 |
#undef cpu_has_apic
|
|
Packit |
577717 |
#define cpu_has_apic 0
|
|
Packit |
577717 |
#undef apic_write
|
|
Packit |
577717 |
#define apic_write(reg,vector) do{}while(0)
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if defined(CONFIG_SMP)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void
|
|
Packit |
577717 |
set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
state->k1.isuspend_cpu = cpu;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline int
|
|
Packit |
577717 |
is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return state->k1.isuspend_cpu == cpu;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
state->k1.isuspend_cpu = NR_CPUS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#else /* CONFIG_SMP */
|
|
Packit |
577717 |
static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { }
|
|
Packit |
577717 |
static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; }
|
|
Packit |
577717 |
static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
|
|
Packit |
577717 |
#endif /* CONFIG_SMP */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/****************************************************************
|
|
Packit |
577717 |
* *
|
|
Packit |
577717 |
* Driver procedures. *
|
|
Packit |
577717 |
* *
|
|
Packit |
577717 |
****************************************************************/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Intel P5 family (Pentium, family code 5).
|
|
Packit |
577717 |
* - One TSC and two 40-bit PMCs.
|
|
Packit |
577717 |
* - A single 32-bit CESR (MSR 0x11) controls both PMCs.
|
|
Packit |
577717 |
* CESR has two halves, each controlling one PMC.
|
|
Packit |
577717 |
* To keep the API reasonably clean, the user puts 16 bits of
|
|
Packit |
577717 |
* control data in each counter's evntsel; the driver combines
|
|
Packit |
577717 |
* these to a single 32-bit CESR value.
|
|
Packit |
577717 |
* - Overflow interrupts are not available.
|
|
Packit |
577717 |
* - Pentium MMX added the RDPMC instruction. RDPMC has lower
|
|
Packit |
577717 |
* overhead than RDMSR and it can be used in user-mode code.
|
|
Packit |
577717 |
* - The MMX events are not symmetric: some events are only available
|
|
Packit |
577717 |
* for some PMC, and some event codes denote different events
|
|
Packit |
577717 |
* depending on which PMCs they control.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* shared with MII and C6 */
|
|
Packit |
577717 |
static int p5_like_check_control(struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
unsigned int reserved_bits, int is_c6)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned short cesr_half[2];
|
|
Packit |
577717 |
unsigned int pmc, evntsel, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (state->control.nrictrs != 0 || state->control.nractrs > 2)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
cesr_half[0] = 0;
|
|
Packit |
577717 |
cesr_half[1] = 0;
|
|
Packit |
577717 |
for(i = 0; i < state->control.nractrs; ++i) {
|
|
Packit |
577717 |
pmc = state->control.pmc_map[i];
|
|
Packit |
577717 |
state->pmc[i].map = pmc;
|
|
Packit |
577717 |
if (pmc > 1 || cesr_half[pmc] != 0)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
evntsel = state->control.evntsel[i];
|
|
Packit |
577717 |
/* protect reserved bits */
|
|
Packit |
577717 |
if ((evntsel & reserved_bits) != 0)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
/* the CPL field (if defined) must be non-zero */
|
|
Packit |
577717 |
if (!is_c6 && !(evntsel & P5_CESR_CPL))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
cesr_half[pmc] = evntsel;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
state->k1.id = (cesr_half[1] << 16) | cesr_half[0];
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int p5_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return p5_like_check_control(state, P5_CESR_RESERVED, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* shared with MII but not C6 */
|
|
Packit |
577717 |
static void p5_write_control(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
unsigned int cesr;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cesr = state->k1.id;
|
|
Packit |
577717 |
if (!cesr) /* no PMC is on (this test doesn't work on C6) */
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
cache = get_cpu_cache();
|
|
Packit |
577717 |
if (cache->k1.p5_cesr != cesr) {
|
|
Packit |
577717 |
cache->k1.p5_cesr = cesr;
|
|
Packit |
577717 |
wrmsr(MSR_P5_CESR, cesr, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void p5_read_counters(const struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
struct perfctr_low_ctrs *ctrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int cstatus, nrctrs, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* The P5 doesn't allocate a cache line on a write miss, so do
|
|
Packit |
577717 |
a dummy read to avoid a write miss here _and_ a read miss
|
|
Packit |
577717 |
later in our caller. */
|
|
Packit |
577717 |
asm("" : : "r"(ctrs->tsc));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
if (perfctr_cstatus_has_tsc(cstatus))
|
|
Packit |
577717 |
rdtscl(ctrs->tsc);
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nractrs(cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int pmc = state->pmc[i].map;
|
|
Packit |
577717 |
rdmsr_low(MSR_P5_CTR0+pmc, ctrs->pmc[i]);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* used by all except pre-MMX P5 */
|
|
Packit |
577717 |
static void rdpmc_read_counters(const struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
struct perfctr_low_ctrs *ctrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int cstatus, nrctrs, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
if (perfctr_cstatus_has_tsc(cstatus))
|
|
Packit |
577717 |
rdtscl(ctrs->tsc);
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nractrs(cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int pmc = state->pmc[i].map;
|
|
Packit |
577717 |
rdpmc_low(pmc, ctrs->pmc[i]);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* shared with MII and C6 */
|
|
Packit |
577717 |
static const struct perfctr_msr_range p5_extras[] = {
|
|
Packit |
577717 |
{ MSR_P5_CESR, 1+2 },
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs p5_pmu_msrs = {
|
|
Packit |
577717 |
.extras = p5_extras,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Cyrix 6x86/MII/III.
|
|
Packit |
577717 |
* - Same MSR assignments as P5 MMX. Has RDPMC and two 48-bit PMCs.
|
|
Packit |
577717 |
* - Event codes and CESR formatting as in the plain P5 subset.
|
|
Packit |
577717 |
* - Many but not all P5 MMX event codes are implemented.
|
|
Packit |
577717 |
* - Cyrix adds a few more event codes. The event code is widened
|
|
Packit |
577717 |
* to 7 bits, and Cyrix puts the high bit in CESR bit 10
|
|
Packit |
577717 |
* (and CESR bit 26 for PMC1).
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int mii_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return p5_like_check_control(state, MII_CESR_RESERVED, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Centaur WinChip C6/2/3.
|
|
Packit |
577717 |
* - Same MSR assignments as P5 MMX. Has RDPMC and two 40-bit PMCs.
|
|
Packit |
577717 |
* - CESR is formatted with two halves, like P5. However, there
|
|
Packit |
577717 |
* are no defined control fields for e.g. CPL selection, and
|
|
Packit |
577717 |
* there is no defined method for stopping the counters.
|
|
Packit |
577717 |
* - Only a few event codes are defined.
|
|
Packit |
577717 |
* - The 64-bit TSC is synthesised from the low 32 bits of the
|
|
Packit |
577717 |
* two PMCs, and CESR has to be set up appropriately.
|
|
Packit |
577717 |
* Reprogramming CESR causes RDTSC to yield invalid results.
|
|
Packit |
577717 |
* (The C6 may also hang in this case, due to C6 erratum I-13.)
|
|
Packit |
577717 |
* Therefore, using the PMCs on any of these processors requires
|
|
Packit |
577717 |
* that the TSC is not accessed at all:
|
|
Packit |
577717 |
* 1. The kernel must be configured or a TSC-less processor, i.e.
|
|
Packit |
577717 |
* generic 586 or less.
|
|
Packit |
577717 |
* 2. The "notsc" boot parameter must be passed to the kernel.
|
|
Packit |
577717 |
* 3. User-space libraries and code must also be configured and
|
|
Packit |
577717 |
* compiled for a generic 586 or less.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if !defined(CONFIG_X86_TSC)
|
|
Packit |
577717 |
static int c6_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (state->control.tsc_on)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
return p5_like_check_control(state, C6_CESR_RESERVED, 1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void c6_write_control(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
unsigned int cesr;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perfctr_cstatus_nractrs(state->cstatus) == 0) /* no PMC is on */
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
cache = get_cpu_cache();
|
|
Packit |
577717 |
cesr = state->k1.id;
|
|
Packit |
577717 |
if (cache->k1.p5_cesr != cesr) {
|
|
Packit |
577717 |
cache->k1.p5_cesr = cesr;
|
|
Packit |
577717 |
wrmsr(MSR_P5_CESR, cesr, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif /* !CONFIG_X86_TSC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Intel P6 family (Pentium Pro, Pentium II, Pentium III, Pentium M,
|
|
Packit |
577717 |
* Intel Core, Intel Core 2, Atom, and Core i7, including Xeon and Celeron versions.
|
|
Packit |
577717 |
* - One TSC and two 40-bit PMCs.
|
|
Packit |
577717 |
* Core i7 has four 48-bit PMCs.
|
|
Packit |
577717 |
* - One 32-bit EVNTSEL MSR for each PMC.
|
|
Packit |
577717 |
* - EVNTSEL0 contains a global enable/disable bit.
|
|
Packit |
577717 |
* That bit is reserved in EVNTSEL1.
|
|
Packit |
577717 |
* On Core 2, Atom, and Core i7 each EVNTSEL has its own enable/disable bit.
|
|
Packit |
577717 |
* - Each EVNTSEL contains a CPL field.
|
|
Packit |
577717 |
* - Overflow interrupts are possible, but requires that the
|
|
Packit |
577717 |
* local APIC is available. Some Mobile P6s have no local APIC.
|
|
Packit |
577717 |
* - The PMCs cannot be initialised with arbitrary values, since
|
|
Packit |
577717 |
* wrmsr fills the high bits by sign-extending from bit 31.
|
|
Packit |
577717 |
* - Most events are symmetric, but a few are not.
|
|
Packit |
577717 |
* - Core 2 adds three fixed-function counters. A single shared control
|
|
Packit |
577717 |
* register has the control bits (CPL:2 + PMI:1) for these counters.
|
|
Packit |
577717 |
* - Initial Atoms appear to have one fixed-function counter.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int is_fam10h;
|
|
Packit |
577717 |
static int amd_is_multicore; /* northbridge events need special care */
|
|
Packit |
577717 |
static int amd_is_k8_mc_RevE;
|
|
Packit |
577717 |
static cpumask_t amd_mc_core0_mask; /* only these may use NB events */
|
|
Packit |
577717 |
static int p6_has_separate_enables; /* affects EVNTSEL.ENable rules */
|
|
Packit |
577717 |
static unsigned int p6_nr_pmcs; /* number of general-purpose counters */
|
|
Packit |
577717 |
static unsigned int p6_nr_ffcs; /* number of fixed-function counters */
|
|
Packit |
577717 |
static unsigned int nhlm_nr_offcore_rsps; /* number of OFFCORE_RSP MSRs */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* shared with K7 */
|
|
Packit |
577717 |
static int p6_like_check_control(struct perfctr_cpu_state *state, int is_k7, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int evntsel, i, nractrs, nrctrs, pmc_mask, pmc;
|
|
Packit |
577717 |
unsigned int core2_fixed_ctr_ctrl;
|
|
Packit |
577717 |
unsigned int max_nrctrs;
|
|
Packit |
577717 |
unsigned int amd_mc_nb_event_seen;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
max_nrctrs = is_k7 ? 4 : p6_nr_pmcs + p6_nr_ffcs;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
nractrs = state->control.nractrs;
|
|
Packit |
577717 |
nrctrs = nractrs + state->control.nrictrs;
|
|
Packit |
577717 |
if (nrctrs < nractrs || nrctrs > max_nrctrs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmc_mask = 0;
|
|
Packit |
577717 |
core2_fixed_ctr_ctrl = 0; /* must be zero on CPUs != Core 2 */
|
|
Packit |
577717 |
amd_mc_nb_event_seen = 0;
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i) {
|
|
Packit |
577717 |
pmc = state->control.pmc_map[i];
|
|
Packit |
577717 |
state->pmc[i].map = pmc;
|
|
Packit |
577717 |
/* pmc_map[i] is what we pass to RDPMC
|
|
Packit |
577717 |
* to check that pmc_map[] is well-defined on Core 2,
|
|
Packit |
577717 |
* we map FIXED_CTR 0x40000000+N to PMC p6_nr_pmcs+N
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (!is_k7 && p6_nr_ffcs != 0) {
|
|
Packit |
577717 |
if (pmc & CORE2_PMC_FIXED_FLAG)
|
|
Packit |
577717 |
pmc = p6_nr_pmcs + (pmc & ~CORE2_PMC_FIXED_FLAG);
|
|
Packit |
577717 |
else if (pmc >= p6_nr_pmcs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (pmc >= max_nrctrs || (pmc_mask & (1<
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
pmc_mask |= (1<
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check evntsel_high on AMD Fam10h
|
|
Packit |
577717 |
* on others we force it to zero (should return -EINVAL but
|
|
Packit |
577717 |
* having zeroes there has not been a requirement before)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (is_fam10h) {
|
|
Packit |
577717 |
unsigned int evntsel_high = state->control.evntsel_high[i];
|
|
Packit |
577717 |
if (evntsel_high & FAM10H_EVNTSEL_HIGH_RESERVED)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
} else
|
|
Packit |
577717 |
state->control.evntsel_high[i] = 0;
|
|
Packit |
577717 |
/* check evntsel */
|
|
Packit |
577717 |
evntsel = state->control.evntsel[i];
|
|
Packit |
577717 |
/* handle per-thread counting of AMD multicore northbridge events */
|
|
Packit |
577717 |
if (cpumask != NULL && amd_is_multicore && IS_K8_NB_EVENT(evntsel)) {
|
|
Packit |
577717 |
/* K8 RevE NB event erratum is incompatible with per-thread counters */
|
|
Packit |
577717 |
if (amd_is_k8_mc_RevE)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
/* remember to restrict this session to amd_mc_core0_mask */
|
|
Packit |
577717 |
amd_mc_nb_event_seen = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* protect reserved bits */
|
|
Packit |
577717 |
if (evntsel & P6_EVNTSEL_RESERVED)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
/* check ENable bit */
|
|
Packit |
577717 |
if (is_k7 || p6_has_separate_enables) {
|
|
Packit |
577717 |
/* ENable bit must be set in each evntsel */
|
|
Packit |
577717 |
if (!(evntsel & P6_EVNTSEL_ENABLE))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
/* only evntsel[0] has the ENable bit */
|
|
Packit |
577717 |
if (evntsel & P6_EVNTSEL_ENABLE) {
|
|
Packit |
577717 |
if (pmc > 0)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
if (pmc == 0)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* the CPL field must be non-zero */
|
|
Packit |
577717 |
if (!(evntsel & P6_EVNTSEL_CPL))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
/* INT bit must be off for a-mode and on for i-mode counters */
|
|
Packit |
577717 |
if (evntsel & P6_EVNTSEL_INT) {
|
|
Packit |
577717 |
if (i < nractrs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
if (i >= nractrs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!is_k7 && p6_nr_ffcs != 0) {
|
|
Packit |
577717 |
pmc = state->control.pmc_map[i];
|
|
Packit |
577717 |
if (pmc & CORE2_PMC_FIXED_FLAG) {
|
|
Packit |
577717 |
unsigned int ctl = 0;
|
|
Packit |
577717 |
ctl |= ((evntsel >> 17) & 1) << 0; /* CPL.OS */
|
|
Packit |
577717 |
ctl |= ((evntsel >> 16) & 1) << 1; /* CPL.USR */
|
|
Packit |
577717 |
ctl |= ((evntsel >> 20) & 1) << 3; /* INT/PMI */
|
|
Packit |
577717 |
core2_fixed_ctr_ctrl |= ctl << (pmc & CORE2_PMC_FIXED_MASK) * 4;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check offcore_rsp[] on Intel Nehalem
|
|
Packit |
577717 |
* on others we force it to zero (should return -EINVAL but
|
|
Packit |
577717 |
* having zeroes there has not been a requirement before)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (i = 0; i < 2; ++i) {
|
|
Packit |
577717 |
if (i < nhlm_nr_offcore_rsps) {
|
|
Packit |
577717 |
unsigned int offcore_rsp = state->control.nhlm.offcore_rsp[i];
|
|
Packit |
577717 |
if (offcore_rsp & OFFCORE_RSP_RESERVED)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
} else
|
|
Packit |
577717 |
state->control.nhlm.offcore_rsp[i] = 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
state->core2_fixed_ctr_ctrl = core2_fixed_ctr_ctrl;
|
|
Packit |
577717 |
state->k1.id = new_id();
|
|
Packit |
577717 |
if (amd_mc_nb_event_seen)
|
|
Packit |
577717 |
*cpumask = amd_mc_core0_mask;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int p6_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return p6_like_check_control(state, 0, cpumask);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
|
|
Packit |
577717 |
/* shared with K7 and P4 */
|
|
Packit |
577717 |
static void p6_like_isuspend(struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
unsigned int msr_evntsel0)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
unsigned int cstatus, nrctrs, i;
|
|
Packit |
577717 |
int cpu;
|
|
Packit |
577717 |
unsigned int pending = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpu = smp_processor_id();
|
|
Packit |
577717 |
set_isuspend_cpu(state, cpu); /* early to limit cpu's live range */
|
|
Packit |
577717 |
cache = __get_cpu_cache(cpu);
|
|
Packit |
577717 |
perfctr_cpu_mask_interrupts(cache);
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nrctrs(cstatus);
|
|
Packit |
577717 |
if (state->core2_fixed_ctr_ctrl & MSR_CORE_PERF_FIXED_CTR_CTRL_PMIANY) {
|
|
Packit |
577717 |
cache->core2_fixed_ctr_ctrl = 0;
|
|
Packit |
577717 |
wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int pmc_raw, pmc_idx, now;
|
|
Packit |
577717 |
pmc_raw = state->pmc[i].map;
|
|
Packit |
577717 |
if (!(pmc_raw & CORE2_PMC_FIXED_FLAG)) {
|
|
Packit |
577717 |
/* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7.
|
|
Packit |
577717 |
We don't need to make it into a parameter. */
|
|
Packit |
577717 |
pmc_idx = pmc_raw & P4_MASK_FAST_RDPMC;
|
|
Packit |
577717 |
cache->control.evntsel[pmc_idx] = 0;
|
|
Packit |
577717 |
cache->control.evntsel_high[pmc_idx] = 0;
|
|
Packit |
577717 |
/* On P4 this intensionally also clears the CCCR.OVF flag. */
|
|
Packit |
577717 |
wrmsr(msr_evntsel0+pmc_idx, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* P4 erratum N17 does not apply since we read only low 32 bits. */
|
|
Packit |
577717 |
rdpmc_low(pmc_raw, now);
|
|
Packit |
577717 |
state->pmc[i].sum += now - state->pmc[i].start;
|
|
Packit |
577717 |
state->pmc[i].start = now;
|
|
Packit |
577717 |
if ((int)now >= 0)
|
|
Packit |
577717 |
++pending;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
state->pending_interrupt = pending;
|
|
Packit |
577717 |
/* cache->k1.id is still == state->k1.id */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
|
|
Packit |
577717 |
/* shared with K7 and P4 */
|
|
Packit |
577717 |
static void p6_like_iresume(const struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
unsigned int msr_evntsel0,
|
|
Packit |
577717 |
unsigned int msr_perfctr0)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
unsigned int cstatus, nrctrs, i;
|
|
Packit |
577717 |
int cpu;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpu = smp_processor_id();
|
|
Packit |
577717 |
cache = __get_cpu_cache(cpu);
|
|
Packit |
577717 |
perfctr_cpu_unmask_interrupts(cache);
|
|
Packit |
577717 |
if (cache->k1.id == state->k1.id) {
|
|
Packit |
577717 |
cache->k1.id = 0; /* force reload of cleared EVNTSELs */
|
|
Packit |
577717 |
if (is_isuspend_cpu(state, cpu))
|
|
Packit |
577717 |
return; /* skip reload of PERFCTRs */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nrctrs(cstatus);
|
|
Packit |
577717 |
/* If the control wasn't ours we must disable the
|
|
Packit |
577717 |
counters before reinitialising them. */
|
|
Packit |
577717 |
if ((state->core2_fixed_ctr_ctrl & MSR_CORE_PERF_FIXED_CTR_CTRL_PMIANY) &&
|
|
Packit |
577717 |
cache->core2_fixed_ctr_ctrl != 0) {
|
|
Packit |
577717 |
cache->core2_fixed_ctr_ctrl = 0;
|
|
Packit |
577717 |
wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int pmc_raw = state->pmc[i].map;
|
|
Packit |
577717 |
unsigned int msr_perfctr;
|
|
Packit |
577717 |
unsigned int pmc_value_hi;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pmc_raw & CORE2_PMC_FIXED_FLAG) {
|
|
Packit |
577717 |
msr_perfctr = MSR_CORE_PERF_FIXED_CTR0 + (pmc_raw & CORE2_PMC_FIXED_MASK);
|
|
Packit |
577717 |
/* Limit the value written to a fixed-function counter's MSR
|
|
Packit |
577717 |
* to 40 bits. Extraneous high bits cause GP faults on Model 23
|
|
Packit |
577717 |
* Core2s, while earlier processors would just ignore them.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
pmc_value_hi = 0xff;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
/* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7.
|
|
Packit |
577717 |
We don't need to make it into a parameter. */
|
|
Packit |
577717 |
unsigned int pmc_idx = pmc_raw & P4_MASK_FAST_RDPMC;
|
|
Packit |
577717 |
/* If the control wasn't ours we must disable the evntsels
|
|
Packit |
577717 |
before reinitialising the counters, to prevent unexpected
|
|
Packit |
577717 |
counter increments and missed overflow interrupts. */
|
|
Packit |
577717 |
if (cache->control.evntsel[pmc_idx]) {
|
|
Packit |
577717 |
cache->control.evntsel[pmc_idx] = 0;
|
|
Packit |
577717 |
cache->control.evntsel_high[pmc_idx] = 0;
|
|
Packit |
577717 |
wrmsr(msr_evntsel0+pmc_idx, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
msr_perfctr = msr_perfctr0 + pmc_idx;
|
|
Packit |
577717 |
pmc_value_hi = -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* P4 erratum N15 does not apply since the CCCR is disabled. */
|
|
Packit |
577717 |
wrmsr(msr_perfctr, state->pmc[i].start, pmc_value_hi);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* cache->k1.id remains != state->k1.id */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void p6_isuspend(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
p6_like_isuspend(state, MSR_P6_EVNTSEL0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void p6_iresume(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
p6_like_iresume(state, MSR_P6_EVNTSEL0, MSR_P6_PERFCTR0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* shared with K7 and VC3 */
|
|
Packit |
577717 |
static void p6_like_write_control(const struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
unsigned int msr_evntsel0)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
unsigned int nrctrs, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cache = get_cpu_cache();
|
|
Packit |
577717 |
if (cache->k1.id == state->k1.id)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int pmc, evntsel, evntsel_high;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmc = state->pmc[i].map;
|
|
Packit |
577717 |
if (pmc & CORE2_PMC_FIXED_FLAG)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
evntsel = state->control.evntsel[i];
|
|
Packit |
577717 |
evntsel_high = state->control.evntsel_high[i];
|
|
Packit |
577717 |
if (evntsel != cache->control.evntsel[pmc] ||
|
|
Packit |
577717 |
evntsel_high != cache->control.evntsel_high[pmc]) {
|
|
Packit |
577717 |
cache->control.evntsel[pmc] = evntsel;
|
|
Packit |
577717 |
cache->control.evntsel_high[pmc] = evntsel_high;
|
|
Packit |
577717 |
wrmsr(msr_evntsel0+pmc, evntsel, evntsel_high);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (state->core2_fixed_ctr_ctrl != 0 &&
|
|
Packit |
577717 |
state->core2_fixed_ctr_ctrl != cache->core2_fixed_ctr_ctrl) {
|
|
Packit |
577717 |
cache->core2_fixed_ctr_ctrl = state->core2_fixed_ctr_ctrl;
|
|
Packit |
577717 |
wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, state->core2_fixed_ctr_ctrl, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
for (i = 0; i < 2; ++i) {
|
|
Packit |
577717 |
unsigned int offcore_rsp;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
offcore_rsp = state->control.nhlm.offcore_rsp[i];
|
|
Packit |
577717 |
if (offcore_rsp != cache->nhlm_offcore_rsp[i]) {
|
|
Packit |
577717 |
cache->nhlm_offcore_rsp[i] = offcore_rsp;
|
|
Packit |
577717 |
wrmsr(MSR_OFFCORE_RSP0+i, offcore_rsp, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cache->k1.id = state->k1.id;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* shared with VC3, Generic*/
|
|
Packit |
577717 |
static void p6_write_control(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
p6_like_write_control(state, MSR_P6_EVNTSEL0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct perfctr_msr_range p6_perfctrs[] = {
|
|
Packit |
577717 |
{ MSR_P6_PERFCTR0, 2 }, /* on Core i7 we'll update this count */
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct perfctr_msr_range p6_evntsels[] = {
|
|
Packit |
577717 |
{ MSR_P6_EVNTSEL0, 2 }, /* on Core i7 we'll update this count */
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs p6_pmu_msrs = {
|
|
Packit |
577717 |
.perfctrs = p6_perfctrs,
|
|
Packit |
577717 |
.evntsels = p6_evntsels,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct perfctr_msr_range core2_extras[] = {
|
|
Packit |
577717 |
{ MSR_CORE_PERF_FIXED_CTR0, 3 }, /* on Atom we'll update this count */
|
|
Packit |
577717 |
{ MSR_CORE_PERF_FIXED_CTR_CTRL, 1 },
|
|
Packit |
577717 |
{ MSR_OFFCORE_RSP0, 0 }, /* on Nehalem we'll update this count */
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void core2_clear_counters(int init)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (init) {
|
|
Packit |
577717 |
unsigned int low, high;
|
|
Packit |
577717 |
rdmsr(MSR_IA32_DEBUGCTLMSR, low, high);
|
|
Packit |
577717 |
low &= ~MSR_IA32_DEBUGCTLMSR_FREEZE_PERFMON_ON_PMI;
|
|
Packit |
577717 |
wrmsr(MSR_IA32_DEBUGCTLMSR, low, high);
|
|
Packit |
577717 |
wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, (1 << p6_nr_pmcs) - 1, (1 << p6_nr_ffcs) - 1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs core2_pmu_msrs = {
|
|
Packit |
577717 |
.perfctrs = p6_perfctrs,
|
|
Packit |
577717 |
.evntsels = p6_evntsels,
|
|
Packit |
577717 |
.extras = core2_extras,
|
|
Packit |
577717 |
.clear_counters = core2_clear_counters,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* AMD K7 family (Athlon, Duron).
|
|
Packit |
577717 |
* - Somewhat similar to the Intel P6 family.
|
|
Packit |
577717 |
* - Four 48-bit PMCs.
|
|
Packit |
577717 |
* - Four 32-bit EVNTSEL MSRs with similar layout as in P6.
|
|
Packit |
577717 |
* - Completely different MSR assignments :-(
|
|
Packit |
577717 |
* - Fewer countable events defined :-(
|
|
Packit |
577717 |
* - The events appear to be completely symmetric.
|
|
Packit |
577717 |
* - The EVNTSEL MSRs are symmetric since each has its own enable bit.
|
|
Packit |
577717 |
* - Publicly available documentation is incomplete.
|
|
Packit |
577717 |
* - K7 model 1 does not have a local APIC. AMD Document #22007
|
|
Packit |
577717 |
* Revision J hints that it may use debug interrupts instead.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The K8 has the same hardware layout as the K7. It also has
|
|
Packit |
577717 |
* better documentation and a different set of available events.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* AMD Family 10h is similar to the K7, but the EVNTSEL MSRs
|
|
Packit |
577717 |
* have been widened to 64 bits.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int k7_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return p6_like_check_control(state, 1, cpumask);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
static void k7_isuspend(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
p6_like_isuspend(state, MSR_K7_EVNTSEL0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void k7_iresume(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
p6_like_iresume(state, MSR_K7_EVNTSEL0, MSR_K7_PERFCTR0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void k7_write_control(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
p6_like_write_control(state, MSR_K7_EVNTSEL0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_msr_range k7_perfctrs[] = {
|
|
Packit |
577717 |
{ MSR_K7_PERFCTR0, 4 },
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_msr_range k7_evntsels[] = {
|
|
Packit |
577717 |
{ MSR_K7_EVNTSEL0, 4 },
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs k7_pmu_msrs = {
|
|
Packit |
577717 |
.perfctrs = k7_perfctrs,
|
|
Packit |
577717 |
.evntsels = k7_evntsels,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* VIA C3 family.
|
|
Packit |
577717 |
* - A Centaur design somewhat similar to the P6/Celeron.
|
|
Packit |
577717 |
* - PERFCTR0 is an alias for the TSC, and EVNTSEL0 is read-only.
|
|
Packit |
577717 |
* - PERFCTR1 is 32 bits wide.
|
|
Packit |
577717 |
* - EVNTSEL1 has no defined control fields, and there is no
|
|
Packit |
577717 |
* defined method for stopping the counter.
|
|
Packit |
577717 |
* - According to testing, the reserved fields in EVNTSEL1 have
|
|
Packit |
577717 |
* no function. We always fill them with zeroes.
|
|
Packit |
577717 |
* - Only a few event codes are defined.
|
|
Packit |
577717 |
* - No local APIC or interrupt-mode support.
|
|
Packit |
577717 |
* - pmc_map[0] must be 1, if nractrs == 1.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int vc3_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (state->control.nrictrs || state->control.nractrs > 1)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
if (state->control.nractrs == 1) {
|
|
Packit |
577717 |
if (state->control.pmc_map[0] != 1)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
state->pmc[0].map = 1;
|
|
Packit |
577717 |
if (state->control.evntsel[0] & VC3_EVNTSEL1_RESERVED)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
state->k1.id = state->control.evntsel[0];
|
|
Packit |
577717 |
} else
|
|
Packit |
577717 |
state->k1.id = 0;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void vc3_clear_counters(int init)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* Not documented, but seems to be default after boot. */
|
|
Packit |
577717 |
wrmsr(MSR_P6_EVNTSEL0+1, 0x00070079, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs vc3_pmu_msrs = {
|
|
Packit |
577717 |
.clear_counters = vc3_clear_counters,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Intel Pentium 4.
|
|
Packit |
577717 |
* Current implementation restrictions:
|
|
Packit |
577717 |
* - No DS/PEBS support.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Known quirks:
|
|
Packit |
577717 |
* - OVF_PMI+FORCE_OVF counters must have an ireset value of -1.
|
|
Packit |
577717 |
* This allows the regular overflow check to also handle FORCE_OVF
|
|
Packit |
577717 |
* counters. Not having this restriction would lead to MAJOR
|
|
Packit |
577717 |
* complications in the driver's "detect overflow counters" code.
|
|
Packit |
577717 |
* There is no loss of functionality since the ireset value doesn't
|
|
Packit |
577717 |
* affect the counter's PMI rate for FORCE_OVF counters.
|
|
Packit |
577717 |
* - In experiments with FORCE_OVF counters, and regular OVF_PMI
|
|
Packit |
577717 |
* counters with small ireset values between -8 and -1, it appears
|
|
Packit |
577717 |
* that the faulting instruction is subjected to a new PMI before
|
|
Packit |
577717 |
* it can complete, ad infinitum. This occurs even though the driver
|
|
Packit |
577717 |
* clears the CCCR (and in testing also the ESCR) and invokes a
|
|
Packit |
577717 |
* user-space signal handler before restoring the CCCR and resuming
|
|
Packit |
577717 |
* the instruction.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Table 15-4 in the IA32 Volume 3 manual contains a 18x8 entry mapping
|
|
Packit |
577717 |
* from counter/CCCR number (0-17) and ESCR SELECT value (0-7) to the
|
|
Packit |
577717 |
* actual ESCR MSR number. This mapping contains some repeated patterns,
|
|
Packit |
577717 |
* so we can compact it to a 4x8 table of MSR offsets:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* 1. CCCRs 16 and 17 are mapped just like CCCRs 13 and 14, respectively.
|
|
Packit |
577717 |
* Thus, we only consider the 16 CCCRs 0-15.
|
|
Packit |
577717 |
* 2. The CCCRs are organised in pairs, and both CCCRs in a pair use the
|
|
Packit |
577717 |
* same mapping. Thus, we only consider the 8 pairs 0-7.
|
|
Packit |
577717 |
* 3. In each pair of pairs, the second odd-numbered pair has the same domain
|
|
Packit |
577717 |
* as the first even-numbered pair, and the range is 1+ the range of the
|
|
Packit |
577717 |
* the first even-numbered pair. For example, CCCR(0) and (1) map ESCR
|
|
Packit |
577717 |
* SELECT(7) to 0x3A0, and CCCR(2) and (3) map it to 0x3A1.
|
|
Packit |
577717 |
* The only exception is that pair (7) [CCCRs 14 and 15] does not have
|
|
Packit |
577717 |
* ESCR SELECT(3) in its domain, like pair (6) [CCCRs 12 and 13] has.
|
|
Packit |
577717 |
* NOTE: Revisions of IA32 Volume 3 older than #245472-007 had an error
|
|
Packit |
577717 |
* in this table: CCCRs 12, 13, and 16 had their mappings for ESCR SELECT
|
|
Packit |
577717 |
* values 2 and 3 swapped.
|
|
Packit |
577717 |
* 4. All MSR numbers are on the form 0x3??. Instead of storing these as
|
|
Packit |
577717 |
* 16-bit numbers, the table only stores the 8-bit offsets from 0x300.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const unsigned char p4_cccr_escr_map[4][8] = {
|
|
Packit |
577717 |
/* 0x00 and 0x01 as is, 0x02 and 0x03 are +1 */
|
|
Packit |
577717 |
[0x00/4] { [7] 0xA0,
|
|
Packit |
577717 |
[6] 0xA2,
|
|
Packit |
577717 |
[2] 0xAA,
|
|
Packit |
577717 |
[4] 0xAC,
|
|
Packit |
577717 |
[0] 0xB2,
|
|
Packit |
577717 |
[1] 0xB4,
|
|
Packit |
577717 |
[3] 0xB6,
|
|
Packit |
577717 |
[5] 0xC8, },
|
|
Packit |
577717 |
/* 0x04 and 0x05 as is, 0x06 and 0x07 are +1 */
|
|
Packit |
577717 |
[0x04/4] { [0] 0xC0,
|
|
Packit |
577717 |
[2] 0xC2,
|
|
Packit |
577717 |
[1] 0xC4, },
|
|
Packit |
577717 |
/* 0x08 and 0x09 as is, 0x0A and 0x0B are +1 */
|
|
Packit |
577717 |
[0x08/4] { [1] 0xA4,
|
|
Packit |
577717 |
[0] 0xA6,
|
|
Packit |
577717 |
[5] 0xA8,
|
|
Packit |
577717 |
[2] 0xAE,
|
|
Packit |
577717 |
[3] 0xB0, },
|
|
Packit |
577717 |
/* 0x0C, 0x0D, and 0x10 as is,
|
|
Packit |
577717 |
0x0E, 0x0F, and 0x11 are +1 except [3] is not in the domain */
|
|
Packit |
577717 |
[0x0C/4] { [4] 0xB8,
|
|
Packit |
577717 |
[5] 0xCC,
|
|
Packit |
577717 |
[6] 0xE0,
|
|
Packit |
577717 |
[0] 0xBA,
|
|
Packit |
577717 |
[2] 0xBC,
|
|
Packit |
577717 |
[3] 0xBE,
|
|
Packit |
577717 |
[1] 0xCA, },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned int p4_escr_addr(unsigned int pmc, unsigned int cccr_val)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int escr_select, pair, escr_offset;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
escr_select = P4_CCCR_ESCR_SELECT(cccr_val);
|
|
Packit |
577717 |
if (pmc > 0x11)
|
|
Packit |
577717 |
return 0; /* pmc range error */
|
|
Packit |
577717 |
if (pmc > 0x0F)
|
|
Packit |
577717 |
pmc -= 3; /* 0 <= pmc <= 0x0F */
|
|
Packit |
577717 |
pair = pmc / 2; /* 0 <= pair <= 7 */
|
|
Packit |
577717 |
escr_offset = p4_cccr_escr_map[pair / 2][escr_select];
|
|
Packit |
577717 |
if (!escr_offset || (pair == 7 && escr_select == 3))
|
|
Packit |
577717 |
return 0; /* ESCR SELECT range error */
|
|
Packit |
577717 |
return escr_offset + (pair & 1) + 0x300;
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int p4_IQ_ESCR_ok; /* only models <= 2 can use IQ_ESCR{0,1} */
|
|
Packit |
577717 |
static int p4_is_ht; /* affects several CCCR & ESCR fields */
|
|
Packit |
577717 |
static int p4_extended_cascade_ok; /* only models >= 2 can use extended cascading */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int p4_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i, nractrs, nrctrs, pmc_mask;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
nractrs = state->control.nractrs;
|
|
Packit |
577717 |
nrctrs = nractrs + state->control.nrictrs;
|
|
Packit |
577717 |
if (nrctrs < nractrs || nrctrs > 18)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmc_mask = 0;
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int pmc, cccr_val, escr_val, escr_addr;
|
|
Packit |
577717 |
/* check that pmc_map[] is well-defined;
|
|
Packit |
577717 |
pmc_map[i] is what we pass to RDPMC, the PMC itself
|
|
Packit |
577717 |
is extracted by masking off the FAST_RDPMC flag */
|
|
Packit |
577717 |
pmc = state->control.pmc_map[i] & ~P4_FAST_RDPMC;
|
|
Packit |
577717 |
state->pmc[i].map = state->control.pmc_map[i];
|
|
Packit |
577717 |
if (pmc >= 18 || (pmc_mask & (1<
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
pmc_mask |= (1<
|
|
Packit |
577717 |
/* check CCCR contents */
|
|
Packit |
577717 |
cccr_val = state->control.evntsel[i];
|
|
Packit |
577717 |
if (cccr_val & P4_CCCR_RESERVED)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
if (cccr_val & P4_CCCR_EXTENDED_CASCADE) {
|
|
Packit |
577717 |
if (!p4_extended_cascade_ok)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
if (!(pmc == 12 || pmc >= 15))
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if ((cccr_val & P4_CCCR_ACTIVE_THREAD) != P4_CCCR_ACTIVE_THREAD && !p4_is_ht)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
if (!(cccr_val & (P4_CCCR_ENABLE | P4_CCCR_CASCADE | P4_CCCR_EXTENDED_CASCADE)))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
if (cccr_val & P4_CCCR_OVF_PMI_T0) {
|
|
Packit |
577717 |
if (i < nractrs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
if ((cccr_val & P4_CCCR_FORCE_OVF) &&
|
|
Packit |
577717 |
state->control.ireset[i] != -1)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
if (i >= nractrs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* check ESCR contents */
|
|
Packit |
577717 |
escr_val = state->control.p4.escr[i];
|
|
Packit |
577717 |
if (escr_val & P4_ESCR_RESERVED)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
if ((escr_val & P4_ESCR_CPL_T1) && (!p4_is_ht || cpumask != NULL))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
/* compute and cache ESCR address */
|
|
Packit |
577717 |
escr_addr = p4_escr_addr(pmc, cccr_val);
|
|
Packit |
577717 |
if (!escr_addr)
|
|
Packit |
577717 |
return -EINVAL; /* ESCR SELECT range error */
|
|
Packit |
577717 |
/* IQ_ESCR0 and IQ_ESCR1 only exist in models <= 2 */
|
|
Packit |
577717 |
if ((escr_addr & ~0x001) == 0x3BA && !p4_IQ_ESCR_ok)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
/* XXX: Two counters could map to the same ESCR. Should we
|
|
Packit |
577717 |
check that they use the same ESCR value? */
|
|
Packit |
577717 |
state->p4_escr_map[i] = escr_addr - MSR_P4_ESCR0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* check ReplayTagging control (PEBS_ENABLE and PEBS_MATRIX_VERT) */
|
|
Packit |
577717 |
if (state->control.p4.pebs_enable) {
|
|
Packit |
577717 |
if (!nrctrs)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
if (state->control.p4.pebs_enable & P4_PE_RESERVED)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
if (!(state->control.p4.pebs_enable & P4_PE_UOP_TAG))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
if (!(state->control.p4.pebs_enable & P4_PE_REPLAY_TAG_BITS))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
if (state->control.p4.pebs_matrix_vert & P4_PMV_RESERVED)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
if (!(state->control.p4.pebs_matrix_vert & P4_PMV_REPLAY_TAG_BITS))
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
} else if (state->control.p4.pebs_matrix_vert)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
state->k1.id = new_id();
|
|
Packit |
577717 |
if (nrctrs != 0 && cpumask != NULL)
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
|
|
Packit |
577717 |
cpumask_complement(cpumask, &perfctr_cpus_forbidden_mask);
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
cpus_complement(*cpumask, perfctr_cpus_forbidden_mask);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
static void p4_isuspend(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return p6_like_isuspend(state, MSR_P4_CCCR0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void p4_iresume(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return p6_like_iresume(state, MSR_P4_CCCR0, MSR_P4_PERFCTR0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void p4_write_control(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
unsigned int nrctrs, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* XXX: temporary debug check */
|
|
Packit |
577717 |
if (cpu_isset(smp_processor_id(), perfctr_cpus_forbidden_mask) &&
|
|
Packit |
577717 |
perfctr_cstatus_nrctrs(state->cstatus))
|
|
Packit |
577717 |
printk(KERN_ERR "%s: BUG! CPU %u is in the forbidden set\n",
|
|
Packit |
577717 |
__FUNCTION__, smp_processor_id());
|
|
Packit |
577717 |
cache = get_cpu_cache();
|
|
Packit |
577717 |
if (cache->k1.id == state->k1.id)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i) {
|
|
Packit |
577717 |
unsigned int escr_val, escr_off, cccr_val, pmc;
|
|
Packit |
577717 |
escr_val = state->control.p4.escr[i];
|
|
Packit |
577717 |
escr_off = state->p4_escr_map[i];
|
|
Packit |
577717 |
if (escr_val != cache->control.escr[escr_off]) {
|
|
Packit |
577717 |
cache->control.escr[escr_off] = escr_val;
|
|
Packit |
577717 |
wrmsr(MSR_P4_ESCR0+escr_off, escr_val, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cccr_val = state->control.evntsel[i];
|
|
Packit |
577717 |
pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC;
|
|
Packit |
577717 |
if (cccr_val != cache->control.evntsel[pmc]) {
|
|
Packit |
577717 |
cache->control.evntsel[pmc] = cccr_val;
|
|
Packit |
577717 |
wrmsr(MSR_P4_CCCR0+pmc, cccr_val, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (state->control.p4.pebs_enable != cache->control.pebs_enable) {
|
|
Packit |
577717 |
cache->control.pebs_enable = state->control.p4.pebs_enable;
|
|
Packit |
577717 |
wrmsr(MSR_P4_PEBS_ENABLE, state->control.p4.pebs_enable, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (state->control.p4.pebs_matrix_vert != cache->control.pebs_matrix_vert) {
|
|
Packit |
577717 |
cache->control.pebs_matrix_vert = state->control.p4.pebs_matrix_vert;
|
|
Packit |
577717 |
wrmsr(MSR_P4_PEBS_MATRIX_VERT, state->control.p4.pebs_matrix_vert, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cache->k1.id = state->k1.id;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_msr_range p4_perfctrs[] = {
|
|
Packit |
577717 |
{ MSR_P4_PERFCTR0, 18 },
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_msr_range p4_evntsels[] = {
|
|
Packit |
577717 |
{ 0x3BA, 2 }, /* IQ_ESCR{0,1}: only models <= 2 have them */
|
|
Packit |
577717 |
{ 0x3A0, 26 },
|
|
Packit |
577717 |
{ 0x3BC, 3 },
|
|
Packit |
577717 |
{ 0x3C0, 6 },
|
|
Packit |
577717 |
{ 0x3C8, 6 },
|
|
Packit |
577717 |
{ 0x3E0, 2 },
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_msr_range p4_extras[] = {
|
|
Packit |
577717 |
/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
|
|
Packit |
577717 |
docs doesn't fully define it, so leave it alone for now. */
|
|
Packit |
577717 |
/* PEBS_ENABLE and PEBS_MATRIX_VERT handle both PEBS and
|
|
Packit |
577717 |
ReplayTagging, and should exist even if PEBS is disabled */
|
|
Packit |
577717 |
{ 0x3F1, 2 },
|
|
Packit |
577717 |
{ MSR_P4_CCCR0, 18 },
|
|
Packit |
577717 |
{ 0, 0 },
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs p4_pmu_msrs_models_0to2 = {
|
|
Packit |
577717 |
.perfctrs = p4_perfctrs,
|
|
Packit |
577717 |
.evntsels = p4_evntsels,
|
|
Packit |
577717 |
.extras = p4_extras,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs p4_pmu_msrs_models_3up = {
|
|
Packit |
577717 |
.perfctrs = p4_perfctrs,
|
|
Packit |
577717 |
.evntsels = p4_evntsels+1,
|
|
Packit |
577717 |
.extras = p4_extras,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Generic driver for any x86 with a working TSC.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int generic_check_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (state->control.nractrs || state->control.nrictrs)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Driver methods, internal and exported.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Frequently called functions (write_control, read_counters,
|
|
Packit |
577717 |
* isuspend and iresume) are back-patched to invoke the correct
|
|
Packit |
577717 |
* processor-specific methods directly, thereby saving the
|
|
Packit |
577717 |
* overheads of indirect function calls.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Backpatchable call sites must have been "finalised" after
|
|
Packit |
577717 |
* initialisation. The reason for this is that unsynchronised code
|
|
Packit |
577717 |
* modification doesn't work in multiprocessor systems, due to
|
|
Packit |
577717 |
* Intel P6 errata. Consequently, all backpatchable call sites
|
|
Packit |
577717 |
* must be known and local to this file.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Backpatchable calls must initially be to 'noinline' stubs.
|
|
Packit |
577717 |
* Otherwise the compiler may inline the stubs, which breaks
|
|
Packit |
577717 |
* redirect_call() and finalise_backpatching().
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int redirect_call_disable;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static noinline void redirect_call(void *ra, void *to)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* XXX: make this function __init later */
|
|
Packit |
577717 |
if (redirect_call_disable)
|
|
Packit |
577717 |
printk(KERN_ERR __FILE__ ":%s: unresolved call to %p at %p\n",
|
|
Packit |
577717 |
__FUNCTION__, to, ra);
|
|
Packit |
577717 |
/* we can only redirect `call near relative' instructions */
|
|
Packit |
577717 |
if (*((unsigned char*)ra - 5) != 0xE8) {
|
|
Packit |
577717 |
printk(KERN_WARNING __FILE__ ":%s: unable to redirect caller %p to %p\n",
|
|
Packit |
577717 |
__FUNCTION__, ra, to);
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
*(int*)((char*)ra - 4) = (char*)to - (char*)ra;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void (*write_control)(const struct perfctr_cpu_state*);
|
|
Packit |
577717 |
static noinline void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
redirect_call(__builtin_return_address(0), write_control);
|
|
Packit |
577717 |
return write_control(state);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void (*read_counters)(const struct perfctr_cpu_state*,
|
|
Packit |
577717 |
struct perfctr_low_ctrs*);
|
|
Packit |
577717 |
static noinline void perfctr_cpu_read_counters(const struct perfctr_cpu_state *state,
|
|
Packit |
577717 |
struct perfctr_low_ctrs *ctrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
redirect_call(__builtin_return_address(0), read_counters);
|
|
Packit |
577717 |
return read_counters(state, ctrs);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
static void (*cpu_isuspend)(struct perfctr_cpu_state*);
|
|
Packit |
577717 |
static noinline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
redirect_call(__builtin_return_address(0), cpu_isuspend);
|
|
Packit |
577717 |
return cpu_isuspend(state);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void (*cpu_iresume)(const struct perfctr_cpu_state*);
|
|
Packit |
577717 |
static noinline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
redirect_call(__builtin_return_address(0), cpu_iresume);
|
|
Packit |
577717 |
return cpu_iresume(state);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
|
|
Packit |
577717 |
bypass internal caching and force a reload if the I-mode PMCs. */
|
|
Packit |
577717 |
void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#ifdef CONFIG_SMP
|
|
Packit |
577717 |
clear_isuspend_cpu(state);
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
get_cpu_cache()->k1.id = 0;
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
|
|
Packit |
577717 |
static int lvtpc_reinit_needed;
|
|
Packit |
577717 |
unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int cstatus, nrctrs, pmc, pmc_mask;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
pmc = perfctr_cstatus_nractrs(cstatus);
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nrctrs(cstatus);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
state->pending_interrupt = 0;
|
|
Packit |
577717 |
for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
|
|
Packit |
577717 |
if ((int)state->pmc[pmc].start >= 0) { /* XXX: ">" ? */
|
|
Packit |
577717 |
/* XXX: "+=" to correct for overshots */
|
|
Packit |
577717 |
state->pmc[pmc].start = state->control.ireset[pmc];
|
|
Packit |
577717 |
pmc_mask |= (1 << pmc);
|
|
Packit |
577717 |
/* On a P4 we should now clear the OVF flag in the
|
|
Packit |
577717 |
counter's CCCR. However, p4_isuspend() already
|
|
Packit |
577717 |
did that as a side-effect of clearing the CCCR
|
|
Packit |
577717 |
in order to stop the i-mode counters. */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (lvtpc_reinit_needed)
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
|
|
Packit |
577717 |
return pmc_mask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline int check_ireset(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int nrctrs, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
i = state->control.nractrs;
|
|
Packit |
577717 |
nrctrs = i + state->control.nrictrs;
|
|
Packit |
577717 |
for(; i < nrctrs; ++i)
|
|
Packit |
577717 |
if (state->control.ireset[i] >= 0)
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int cstatus, nrctrs, i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nrctrs(cstatus);
|
|
Packit |
577717 |
for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
|
|
Packit |
577717 |
state->pmc[i].start = state->control.ireset[i];
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void debug_no_imode(const struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#ifdef CONFIG_PERFCTR_DEBUG
|
|
Packit |
577717 |
if (perfctr_cstatus_has_ictrs(state->cstatus))
|
|
Packit |
577717 |
printk(KERN_ERR "perfctr/x86.c: BUG! updating control in"
|
|
Packit |
577717 |
" perfctr %p on cpu %u while it has cstatus %x"
|
|
Packit |
577717 |
" (pid %d, comm %s)\n",
|
|
Packit |
577717 |
state, smp_processor_id(), state->cstatus,
|
|
Packit |
577717 |
current->pid, current->comm);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#else /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { }
|
|
Packit |
577717 |
static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { }
|
|
Packit |
577717 |
static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; }
|
|
Packit |
577717 |
static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { }
|
|
Packit |
577717 |
static inline void debug_no_imode(const struct perfctr_cpu_state *state) { }
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int (*check_control)(struct perfctr_cpu_state*, cpumask_t*);
|
|
Packit |
577717 |
int perfctr_cpu_update_control(struct perfctr_cpu_state *state, cpumask_t *cpumask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int err;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
debug_no_imode(state);
|
|
Packit |
577717 |
clear_isuspend_cpu(state);
|
|
Packit |
577717 |
state->cstatus = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* disallow i-mode counters if we cannot catch the interrupts */
|
|
Packit |
577717 |
if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
|
|
Packit |
577717 |
&& state->control.nrictrs)
|
|
Packit |
577717 |
return -EPERM;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
err = check_control(state, cpumask);
|
|
Packit |
577717 |
if (err < 0)
|
|
Packit |
577717 |
return err;
|
|
Packit |
577717 |
err = check_ireset(state);
|
|
Packit |
577717 |
if (err < 0)
|
|
Packit |
577717 |
return err;
|
|
Packit |
577717 |
state->cstatus = perfctr_mk_cstatus(state->control.tsc_on,
|
|
Packit |
577717 |
state->control.nractrs,
|
|
Packit |
577717 |
state->control.nrictrs);
|
|
Packit |
577717 |
setup_imode_start_values(state);
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i, cstatus, nractrs;
|
|
Packit |
577717 |
struct perfctr_low_ctrs now;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (perfctr_cstatus_has_ictrs(state->cstatus))
|
|
Packit |
577717 |
perfctr_cpu_isuspend(state);
|
|
Packit |
577717 |
perfctr_cpu_read_counters(state, &now;;
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
if (perfctr_cstatus_has_tsc(cstatus))
|
|
Packit |
577717 |
state->tsc_sum += now.tsc - state->tsc_start;
|
|
Packit |
577717 |
nractrs = perfctr_cstatus_nractrs(cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nractrs; ++i)
|
|
Packit |
577717 |
state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
|
|
Packit |
577717 |
/* perfctr_cpu_disable_rdpmc(); */ /* not for x86 */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void perfctr_cpu_resume(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (perfctr_cstatus_has_ictrs(state->cstatus))
|
|
Packit |
577717 |
perfctr_cpu_iresume(state);
|
|
Packit |
577717 |
/* perfctr_cpu_enable_rdpmc(); */ /* not for x86 or global-mode */
|
|
Packit |
577717 |
perfctr_cpu_write_control(state);
|
|
Packit |
577717 |
//perfctr_cpu_read_counters(state, &state->start);
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct perfctr_low_ctrs now;
|
|
Packit |
577717 |
unsigned int i, cstatus, nrctrs;
|
|
Packit |
577717 |
perfctr_cpu_read_counters(state, &now;;
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
if (perfctr_cstatus_has_tsc(cstatus))
|
|
Packit |
577717 |
state->tsc_start = now.tsc;
|
|
Packit |
577717 |
nrctrs = perfctr_cstatus_nractrs(cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nrctrs; ++i)
|
|
Packit |
577717 |
state->pmc[i].start = now.pmc[i];
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void perfctr_cpu_sample(struct perfctr_cpu_state *state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i, cstatus, nractrs;
|
|
Packit |
577717 |
struct perfctr_low_ctrs now;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perfctr_cpu_read_counters(state, &now;;
|
|
Packit |
577717 |
cstatus = state->cstatus;
|
|
Packit |
577717 |
if (perfctr_cstatus_has_tsc(cstatus)) {
|
|
Packit |
577717 |
state->tsc_sum += now.tsc - state->tsc_start;
|
|
Packit |
577717 |
state->tsc_start = now.tsc;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
nractrs = perfctr_cstatus_nractrs(cstatus);
|
|
Packit |
577717 |
for(i = 0; i < nractrs; ++i) {
|
|
Packit |
577717 |
state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
|
|
Packit |
577717 |
state->pmc[i].start = now.pmc[i];
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const struct perfctr_pmu_msrs *pmu_msrs;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_cpu_clear_counters(int init)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const struct perfctr_pmu_msrs *pmu;
|
|
Packit |
577717 |
const struct perfctr_msr_range *msrs;
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmu = pmu_msrs;
|
|
Packit |
577717 |
if (!pmu)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* The order below is significant: evntsels must be cleared
|
|
Packit |
577717 |
before the perfctrs. */
|
|
Packit |
577717 |
msrs = pmu->evntsels;
|
|
Packit |
577717 |
if (msrs)
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
clear_msr_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
msrs = pmu->extras;
|
|
Packit |
577717 |
if (msrs)
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
clear_msr_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
msrs = pmu->perfctrs;
|
|
Packit |
577717 |
if (msrs)
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
clear_msr_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
if (pmu->clear_counters)
|
|
Packit |
577717 |
(*pmu->clear_counters)(init);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/****************************************************************
|
|
Packit |
577717 |
* *
|
|
Packit |
577717 |
* Processor detection and initialisation procedures. *
|
|
Packit |
577717 |
* *
|
|
Packit |
577717 |
****************************************************************/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void clear_perfctr_cpus_forbidden_mask(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#if !defined(perfctr_cpus_forbidden_mask)
|
|
Packit |
577717 |
cpus_clear(perfctr_cpus_forbidden_mask);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void set_perfctr_cpus_forbidden_mask(cpumask_t mask)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#if !defined(perfctr_cpus_forbidden_mask)
|
|
Packit |
577717 |
perfctr_cpus_forbidden_mask = mask;
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* see comment above at redirect_call() */
|
|
Packit |
577717 |
static void __init finalise_backpatching(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache;
|
|
Packit |
577717 |
struct perfctr_cpu_state state;
|
|
Packit |
577717 |
cpumask_t old_mask;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
old_mask = perfctr_cpus_forbidden_mask;
|
|
Packit |
577717 |
clear_perfctr_cpus_forbidden_mask();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cache = get_cpu_cache();
|
|
Packit |
577717 |
memset(cache, 0, sizeof *cache);
|
|
Packit |
577717 |
memset(&state, 0, sizeof state);
|
|
Packit |
577717 |
if (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT) {
|
|
Packit |
577717 |
state.cstatus = __perfctr_mk_cstatus(0, 1, 0, 0);
|
|
Packit |
577717 |
perfctr_cpu_sample(&state);
|
|
Packit |
577717 |
perfctr_cpu_resume(&state);
|
|
Packit |
577717 |
perfctr_cpu_suspend(&state);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
state.cstatus = 0;
|
|
Packit |
577717 |
perfctr_cpu_sample(&state);
|
|
Packit |
577717 |
perfctr_cpu_resume(&state);
|
|
Packit |
577717 |
perfctr_cpu_suspend(&state);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
set_perfctr_cpus_forbidden_mask(old_mask);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
redirect_call_disable = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_SMP
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpumask_t perfctr_cpus_forbidden_mask;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline unsigned int find_mask(unsigned int nrvals)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int tmp = nrvals;
|
|
Packit |
577717 |
unsigned int index_msb = 31;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!tmp)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
while (!(tmp & (1<<31))) {
|
|
Packit |
577717 |
tmp <<= 1;
|
|
Packit |
577717 |
--index_msb;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (nrvals & (nrvals - 1))
|
|
Packit |
577717 |
++index_msb;
|
|
Packit |
577717 |
return ~(~0 << index_msb);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init p4_ht_mask_setup_cpu(void *forbidden)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int cpu = smp_processor_id();
|
|
Packit |
577717 |
unsigned int cpuid_maxlev;
|
|
Packit |
577717 |
unsigned int cpuid1_ebx, cpuid1_edx, cpuid4_eax;
|
|
Packit |
577717 |
unsigned int initial_APIC_ID;
|
|
Packit |
577717 |
unsigned int max_cores_per_package;
|
|
Packit |
577717 |
unsigned int max_lp_per_package;
|
|
Packit |
577717 |
unsigned int max_lp_per_core;
|
|
Packit |
577717 |
unsigned int smt_id;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* The following big chunk of code detects the current logical processor's
|
|
Packit |
577717 |
* SMT ID (thread number). This is quite complicated, see AP-485 and Volume 3
|
|
Packit |
577717 |
* of Intel's IA-32 Manual (especially section 7.10) for details.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Ensure that CPUID reports all levels. */
|
|
Packit |
577717 |
if (cpu_data(cpu).x86_model == 3) { /* >= 3? */
|
|
Packit |
577717 |
unsigned int low, high;
|
|
Packit |
577717 |
rdmsr(MSR_IA32_MISC_ENABLE, low, high);
|
|
Packit |
577717 |
if (low & (1<<22)) { /* LIMIT_CPUID_MAXVAL */
|
|
Packit |
577717 |
low &= ~(1<<22);
|
|
Packit |
577717 |
wrmsr(MSR_IA32_MISC_ENABLE, low, high);
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr/x86.c: CPU %d: removed CPUID level limitation\n",
|
|
Packit |
577717 |
cpu);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Find the highest standard CPUID level. */
|
|
Packit |
577717 |
cpuid_maxlev = cpuid_eax(0);
|
|
Packit |
577717 |
if (cpuid_maxlev < 1) {
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr/x86: CPU %d: impossibly low # of CPUID levels: %u\n",
|
|
Packit |
577717 |
cpu, cpuid_maxlev);
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cpuid1_ebx = cpuid_ebx(1);
|
|
Packit |
577717 |
cpuid1_edx = cpuid_edx(1);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Find the initial (HW-assigned) APIC ID of this logical processor. */
|
|
Packit |
577717 |
initial_APIC_ID = cpuid1_ebx >> 24;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Find the max number of logical processors per physical processor package. */
|
|
Packit |
577717 |
if (cpuid1_edx & (1 << 28)) /* HT is supported */
|
|
Packit |
577717 |
max_lp_per_package = (cpuid1_ebx >> 16) & 0xFF;
|
|
Packit |
577717 |
else /* HT is not supported */
|
|
Packit |
577717 |
max_lp_per_package = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Find the max number of processor cores per physical processor package. */
|
|
Packit |
577717 |
if (cpuid_maxlev >= 4) {
|
|
Packit |
577717 |
/* For CPUID level 4 we need a zero in ecx as input to CPUID, but
|
|
Packit |
577717 |
cpuid_eax() doesn't do that. So we resort to using cpuid_count()
|
|
Packit |
577717 |
with reference parameters and dummy outputs. */
|
|
Packit |
577717 |
unsigned int dummy;
|
|
Packit |
577717 |
cpuid_count(4, 0, &cpuid4_eax, &dummy, &dummy, &dummy);
|
|
Packit |
577717 |
max_cores_per_package = (cpuid4_eax >> 26) + 1;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
cpuid4_eax = 0;
|
|
Packit |
577717 |
max_cores_per_package = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
max_lp_per_core = max_lp_per_package / max_cores_per_package;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
smt_id = initial_APIC_ID & find_mask(max_lp_per_core);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr/x86.c: CPU %d: cpuid_ebx(1) 0x%08x, cpuid_edx(1) 0x%08x, cpuid_eax(4) 0x%08x, cpuid_maxlev %u, max_cores_per_package %u, SMT_ID %u\n",
|
|
Packit |
577717 |
cpu, cpuid1_ebx, cpuid1_edx, cpuid4_eax, cpuid_maxlev, max_cores_per_package, smt_id);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Now (finally!) check the SMT ID. The CPU numbers for non-zero SMT ID
|
|
Packit |
577717 |
* threads are recorded in the forbidden set, to allow performance counter
|
|
Packit |
577717 |
* hardware resource conflicts between sibling threads to be prevented.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (smt_id != 0)
|
|
Packit |
577717 |
/* We rely on cpu_set() being atomic! */
|
|
Packit |
577717 |
cpu_set(cpu, *(cpumask_t*)forbidden);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init p4_ht_smp_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
cpumask_t forbidden;
|
|
Packit |
577717 |
unsigned int cpu;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpus_clear(forbidden);
|
|
Packit |
577717 |
smp_call_function(p4_ht_mask_setup_cpu, &forbidden, 1);
|
|
Packit |
577717 |
p4_ht_mask_setup_cpu(&forbidden);
|
|
Packit |
577717 |
if (cpus_empty(forbidden))
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
perfctr_cpus_forbidden_mask = forbidden;
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr/x86.c: hyper-threaded P4s detected:"
|
|
Packit |
577717 |
" restricting access for CPUs");
|
|
Packit |
577717 |
for(cpu = 0; cpu < NR_CPUS; ++cpu)
|
|
Packit |
577717 |
if (cpu_isset(cpu, forbidden))
|
|
Packit |
577717 |
printk(" %u", cpu);
|
|
Packit |
577717 |
printk("\n");
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#else /* SMP */
|
|
Packit |
577717 |
#define p4_ht_smp_init() (0)
|
|
Packit |
577717 |
#endif /* SMP */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init p4_ht_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int nr_siblings;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!cpu_has_ht)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
nr_siblings = (cpuid_ebx(1) >> 16) & 0xFF;
|
|
Packit |
577717 |
if (nr_siblings < 2)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
p4_is_ht = 1; /* needed even in a UP kernel */
|
|
Packit |
577717 |
return p4_ht_smp_init();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init intel_p4_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static char p4_name[] __initdata = "Intel P4";
|
|
Packit |
577717 |
unsigned int misc_enable;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Detect things that matter to the driver. */
|
|
Packit |
577717 |
rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable);
|
|
Packit |
577717 |
if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
if (p4_ht_init() != 0)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
if (current_cpu_data.x86_model <= 2)
|
|
Packit |
577717 |
p4_IQ_ESCR_ok = 1;
|
|
Packit |
577717 |
if (current_cpu_data.x86_model >= 2)
|
|
Packit |
577717 |
p4_extended_cascade_ok = 1;
|
|
Packit |
577717 |
/* Detect and set up legacy cpu_type for user-space. */
|
|
Packit |
577717 |
if (current_cpu_data.x86_model >= 3) {
|
|
Packit |
577717 |
/* Model 3 removes IQ_ESCR{0,1} and adds one event. */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_P4M3;
|
|
Packit |
577717 |
} else if (current_cpu_data.x86_model >= 2) {
|
|
Packit |
577717 |
/* Model 2 changed the ESCR Event Mask programming
|
|
Packit |
577717 |
details for several events. */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_P4M2;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_P4;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_P4);
|
|
Packit |
577717 |
perfctr_cpu_name = p4_name;
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
write_control = p4_write_control;
|
|
Packit |
577717 |
check_control = p4_check_control;
|
|
Packit |
577717 |
if (current_cpu_data.x86_model <= 2)
|
|
Packit |
577717 |
pmu_msrs = &p4_pmu_msrs_models_0to2;
|
|
Packit |
577717 |
else
|
|
Packit |
577717 |
pmu_msrs = &p4_pmu_msrs_models_3up;
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
if (cpu_has_apic) {
|
|
Packit |
577717 |
perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
|
|
Packit |
577717 |
cpu_isuspend = p4_isuspend;
|
|
Packit |
577717 |
cpu_iresume = p4_iresume;
|
|
Packit |
577717 |
lvtpc_reinit_needed = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init intel_p5_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static char p5_name[] __initdata = "Intel P5";
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Detect things that matter to the driver. */
|
|
Packit |
577717 |
if (cpu_has_mmx) {
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Avoid Pentium Erratum 74. */
|
|
Packit |
577717 |
if (current_cpu_data.x86_model == 4 &&
|
|
Packit |
577717 |
(current_cpu_data.x86_mask == 4 ||
|
|
Packit |
577717 |
(current_cpu_data.x86_mask == 3 &&
|
|
Packit |
577717 |
((cpuid_eax(1) >> 12) & 0x3) == 1)))
|
|
Packit |
577717 |
perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
|
|
Packit |
577717 |
read_counters = p5_read_counters;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* Detect and set up legacy cpu_type for user-space. */
|
|
Packit |
577717 |
if (cpu_has_mmx) {
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_P5MMX;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_P5;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_P5);
|
|
Packit |
577717 |
perfctr_cpu_name = p5_name;
|
|
Packit |
577717 |
write_control = p5_write_control;
|
|
Packit |
577717 |
check_control = p5_check_control;
|
|
Packit |
577717 |
pmu_msrs = &p5_pmu_msrs;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init intel_p6_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static char p6_name[] __initdata = "Intel P6";
|
|
Packit |
577717 |
static char core2_name[] __initdata = "Intel Core 2";
|
|
Packit |
577717 |
static char atom_name[] __initdata = "Intel Atom";
|
|
Packit |
577717 |
static char nhlm_name[] __initdata = "Intel Nehalem";
|
|
Packit |
577717 |
static char wstmr_name[] __initdata = "Intel Westmere";
|
|
Packit |
577717 |
unsigned int misc_enable;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Post P4 family 6 models (Pentium M, Core, Core 2, Atom)
|
|
Packit |
577717 |
* have MISC_ENABLE.PERF_AVAIL like the P4.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
switch (current_cpu_data.x86_model) {
|
|
Packit |
577717 |
case 9: /* Pentium M */
|
|
Packit |
577717 |
case 13: /* Pentium M */
|
|
Packit |
577717 |
case 14: /* Core */
|
|
Packit |
577717 |
case 15: /* Core 2 */
|
|
Packit |
577717 |
case 22: /* Core 2 based Celeron model 16h */
|
|
Packit |
577717 |
case 23: /* Core 2 */
|
|
Packit |
577717 |
case 26: /* Nehalem: Core i7-900, Xeon 5500, Xeon 3500 */
|
|
Packit |
577717 |
case 28: /* Atom */
|
|
Packit |
577717 |
case 29: /* Core 2 based Xeon 7400 */
|
|
Packit |
577717 |
case 30: /* Nehalem: Core i7-800/i5-700, i7-900XM/i7-800M/i7-700M, Xeon 3400 */
|
|
Packit |
577717 |
case 37: /* Westmere: Core i5-600/i3-500/Pentium-G6950, i7-600M/i5-500M/i5-400M/i3-300M, Xeno L3406 */
|
|
Packit |
577717 |
case 44: /* Westmere: Core i7-980X (Gulftown), Xeon 5600, Xeon 3600 */
|
|
Packit |
577717 |
case 46: /* Nehalem: Xeon 7500 */
|
|
Packit |
577717 |
rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable);
|
|
Packit |
577717 |
if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Core 2 made each EVNTSEL have its own ENable bit,
|
|
Packit |
577717 |
* and added three fixed-function counters.
|
|
Packit |
577717 |
* On Atom cpuid tells us the number of fixed-function counters.
|
|
Packit |
577717 |
* Core i7 extended the number of PMCs to four.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
p6_nr_pmcs = 2;
|
|
Packit |
577717 |
switch (current_cpu_data.x86_model) {
|
|
Packit |
577717 |
case 15: /* Core 2 */
|
|
Packit |
577717 |
case 22: /* Core 2 based Celeron model 16h */
|
|
Packit |
577717 |
case 23: /* Core 2 */
|
|
Packit |
577717 |
case 29: /* Core 2 based Xeon 7400 */
|
|
Packit |
577717 |
perfctr_cpu_name = core2_name;
|
|
Packit |
577717 |
p6_has_separate_enables = 1;
|
|
Packit |
577717 |
p6_nr_ffcs = 3;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 26: /* Nehalem: Core i7-900, Xeon 5500, Xeon 3500 */
|
|
Packit |
577717 |
case 30: /* Nehalem: Core i7-800/i5-700, i7-900XM/i7-800M/i7-700M, Xeon 3400 */
|
|
Packit |
577717 |
case 46: /* Nehalem: Xeon 7500 */
|
|
Packit |
577717 |
perfctr_cpu_name = nhlm_name;
|
|
Packit |
577717 |
p6_has_separate_enables = 1;
|
|
Packit |
577717 |
p6_nr_ffcs = 3;
|
|
Packit |
577717 |
p6_nr_pmcs = 4;
|
|
Packit |
577717 |
nhlm_nr_offcore_rsps = 1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 37: /* Westmere: Core i5-600/i3-500/Pentium-G6950, i7-600M/i5-500M/i5-400M/i3-300M, Xeon L3406 */
|
|
Packit |
577717 |
case 44: /* Westmere: Core i7-980X (Gulftown), Xeon 5600, Xeon 3600 */
|
|
Packit |
577717 |
perfctr_cpu_name = wstmr_name;
|
|
Packit |
577717 |
p6_has_separate_enables = 1;
|
|
Packit |
577717 |
p6_nr_ffcs = 3;
|
|
Packit |
577717 |
p6_nr_pmcs = 4;
|
|
Packit |
577717 |
/* Westmere adds MSR_OFFCORE_RSP1 and drops some events */
|
|
Packit |
577717 |
nhlm_nr_offcore_rsps = 2;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 28: { /* Atom */
|
|
Packit |
577717 |
unsigned int maxlev, eax, ebx, dummy, edx;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perfctr_cpu_name = atom_name;
|
|
Packit |
577717 |
p6_has_separate_enables = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
maxlev = cpuid_eax(0);
|
|
Packit |
577717 |
if (maxlev < 0xA) {
|
|
Packit |
577717 |
printk(KERN_WARNING "%s: cpuid[0].eax == %u, unable to query 0xA leaf\n",
|
|
Packit |
577717 |
__FUNCTION__, maxlev);
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
cpuid(0xA, &eax, &ebx, &dummy, &edx;;
|
|
Packit |
577717 |
/* ensure we have at least APM V2 with 2 40-bit general-purpose counters */
|
|
Packit |
577717 |
if ((eax & 0xff) < 2 ||
|
|
Packit |
577717 |
((eax >> 8) & 0xff) != 2 ||
|
|
Packit |
577717 |
((eax >> 16) & 0xff) < 40) {
|
|
Packit |
577717 |
printk(KERN_WARNING "%s: cpuid[0xA].eax == 0x%08x appears bogus\n",
|
|
Packit |
577717 |
__FUNCTION__, eax);
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* extract the number of fixed-function counters: Core2 has 3,
|
|
Packit |
577717 |
and initial Atoms appear to have 1; play it safe and reject
|
|
Packit |
577717 |
excessive values */
|
|
Packit |
577717 |
p6_nr_ffcs = edx & 0x1f;
|
|
Packit |
577717 |
if (p6_nr_ffcs > 3) {
|
|
Packit |
577717 |
printk(KERN_WARNING "%s: cpuid[0xA] == { edx == 0x%08x, "
|
|
Packit |
577717 |
"eax == 0x%08x } appears bogus\n",
|
|
Packit |
577717 |
__FUNCTION__, edx, eax);
|
|
Packit |
577717 |
p6_nr_ffcs = 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
perfctr_cpu_name = p6_name;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Avoid Pentium Pro Erratum 26.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (current_cpu_data.x86_model < 3) { /* Pentium Pro */
|
|
Packit |
577717 |
if (current_cpu_data.x86_mask < 9)
|
|
Packit |
577717 |
perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Detect and set up legacy cpu_type for user-space.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
switch (current_cpu_data.x86_model) {
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
printk(KERN_WARNING __FILE__ "%s: unknown model %u processor, "
|
|
Packit |
577717 |
"please report this to perfctr-devel or mikpe@it.uu.se\n",
|
|
Packit |
577717 |
__FUNCTION__, current_cpu_data.x86_model);
|
|
Packit |
577717 |
/*FALLTHROUGH*/
|
|
Packit |
577717 |
case 0: /* Pentium Pro A-step */
|
|
Packit |
577717 |
case 1: /* Pentium Pro */
|
|
Packit |
577717 |
case 4: /* Pentium Pro based P55CT overdrive for P54 */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_P6;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 3: /* Pentium II or PII-based overdrive for PPro */
|
|
Packit |
577717 |
case 5: /* Pentium II */
|
|
Packit |
577717 |
case 6: /* Pentium II */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_PII;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 7: /* Pentium III */
|
|
Packit |
577717 |
case 8: /* Pentium III */
|
|
Packit |
577717 |
case 10: /* Pentium III Xeon model A */
|
|
Packit |
577717 |
case 11: /* Pentium III */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_PIII;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 9: /* Pentium M */
|
|
Packit |
577717 |
case 13: /* Pentium M */
|
|
Packit |
577717 |
/* Erratum Y3 probably does not apply since we
|
|
Packit |
577717 |
read only the low 32 bits. */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_PENTM;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 14: /* Core */
|
|
Packit |
577717 |
/* XXX: what about erratum AE19? */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_CORE;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 15: /* Core 2 */
|
|
Packit |
577717 |
case 22: /* Core 2 based Celeron model 16h */
|
|
Packit |
577717 |
case 23: /* Core 2 */
|
|
Packit |
577717 |
case 29: /* Core 2 based Xeon 7400 */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_CORE2;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 26: /* Nehalem: Core i7-900, Xeon 5500, Xeon 3500 */
|
|
Packit |
577717 |
case 30: /* Nehalem: Core i7-800/i5-700, i7-900XM/i7-800M/i7-700M, Xeon 3400 */
|
|
Packit |
577717 |
case 46: /* Nehalem: Xeon 7500 */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_NHLM;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 37: /* Westmere: Core i5-600/i3-500/Pentium-G6950, i7-600M/i5-500M/i5-400M/i3-300M, Xeon L3406 */
|
|
Packit |
577717 |
case 44: /* Westmere: Core i7-980X (Gulftown), Xeon 5600, Xeon 3600 */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_WSTMR;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 28: /* Atom */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_INTEL_ATOM;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perfctr_set_tests_type(p6_nr_ffcs != 0 ? PTT_CORE2 : PTT_P6);
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
write_control = p6_write_control;
|
|
Packit |
577717 |
check_control = p6_check_control;
|
|
Packit |
577717 |
p6_perfctrs[0].nr_msrs = p6_nr_pmcs;
|
|
Packit |
577717 |
p6_evntsels[0].nr_msrs = p6_nr_pmcs;
|
|
Packit |
577717 |
core2_extras[0].nr_msrs = p6_nr_ffcs;
|
|
Packit |
577717 |
core2_extras[2].nr_msrs = nhlm_nr_offcore_rsps;
|
|
Packit |
577717 |
pmu_msrs = p6_nr_ffcs != 0 ? &core2_pmu_msrs : &p6_pmu_msrs;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
if (cpu_has_apic) {
|
|
Packit |
577717 |
perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
|
|
Packit |
577717 |
cpu_isuspend = p6_isuspend;
|
|
Packit |
577717 |
cpu_iresume = p6_iresume;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Post P4 family 6 models (Pentium M, Core, Core 2, Atom)
|
|
Packit |
577717 |
* have LVTPC auto-masking like the P4.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
switch (current_cpu_data.x86_model) {
|
|
Packit |
577717 |
case 9: /* Pentium M */
|
|
Packit |
577717 |
case 13: /* Pentium M */
|
|
Packit |
577717 |
case 14: /* Core */
|
|
Packit |
577717 |
case 15: /* Core 2 */
|
|
Packit |
577717 |
case 22: /* Core 2 based Celeron model 16h */
|
|
Packit |
577717 |
case 23: /* Core 2 */
|
|
Packit |
577717 |
case 26: /* Nehalem: Core i7-900, Xeon 5500, Xeon 3500 */
|
|
Packit |
577717 |
case 28: /* Atom */
|
|
Packit |
577717 |
case 29: /* Core 2 based Xeon 7400 */
|
|
Packit |
577717 |
case 30: /* Nehalem: Core i7-800/i5-700, i7-900XM/i7-800M/i7-700M, Xeon 3400 */
|
|
Packit |
577717 |
case 37: /* Westmere: Core i5-600/i3-500/Pentium-G6950, i7-600M/i5-500M/i5-400M/i3-300M, Xeon L3406 */
|
|
Packit |
577717 |
case 44: /* Westmere: Core i7-980X (Gulftown), Xeon 5600, Xeon 3600 */
|
|
Packit |
577717 |
case 46: /* Nehalem: Xeon 7500 */
|
|
Packit |
577717 |
lvtpc_reinit_needed = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init intel_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (!cpu_has_tsc)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
switch (current_cpu_data.x86) {
|
|
Packit |
577717 |
case 5:
|
|
Packit |
577717 |
return intel_p5_init();
|
|
Packit |
577717 |
case 6:
|
|
Packit |
577717 |
return intel_p6_init();
|
|
Packit |
577717 |
case 15:
|
|
Packit |
577717 |
return intel_p4_init();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Multicore K8s have issues with northbridge events:
|
|
Packit |
577717 |
* 1. The NB is shared between the cores, so two different cores
|
|
Packit |
577717 |
* in the same node cannot count NB events simultaneously.
|
|
Packit |
577717 |
* This is handled by using a cpumask to restrict NB-using
|
|
Packit |
577717 |
* threads to core0 of all processors.
|
|
Packit |
577717 |
* 2. The initial multicore chips (Revision E) have an erratum
|
|
Packit |
577717 |
* which causes the NB counters to be reset when either core
|
|
Packit |
577717 |
* reprograms its evntsels (even for non-NB events).
|
|
Packit |
577717 |
* This is only an issue because of scheduling of threads, so
|
|
Packit |
577717 |
* we restrict NB events to the non thread-centric API.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#ifdef CONFIG_SMP
|
|
Packit |
577717 |
struct amd_mc_init_data {
|
|
Packit |
577717 |
atomic_t non0core_seen;
|
|
Packit |
577717 |
cpumask_t core0_mask;
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init amd_mc_init_cpu(void *data)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int cpu = smp_processor_id();
|
|
Packit |
577717 |
unsigned int apic_core_id_size, core_id;
|
|
Packit |
577717 |
struct amd_mc_init_data *amd_mc_init_data = data;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if ((cpuid_edx(1) & (1<<28)) == 0 || /* HTT is off */
|
|
Packit |
577717 |
cpuid_eax(0x80000000) < 0x80000008) { /* no Core Count info */
|
|
Packit |
577717 |
/* each processor is single-core */
|
|
Packit |
577717 |
apic_core_id_size = 0;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
unsigned int ecx = cpuid_ecx(0x80000008);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
apic_core_id_size = (ecx >> 12) & 0xF; /* XXX: resvd in early CPUs */
|
|
Packit |
577717 |
if (apic_core_id_size == 0) {
|
|
Packit |
577717 |
unsigned int max_cores = (ecx & 0xFF) + 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
while ((1 << apic_core_id_size) < max_cores)
|
|
Packit |
577717 |
++apic_core_id_size;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
core_id = (cpuid_ebx(1) >> 24) & ((1 << apic_core_id_size) - 1);
|
|
Packit |
577717 |
printk(KERN_INFO "%s: cpu %d core_id %u\n", __FUNCTION__, cpu, core_id);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (core_id != 0) {
|
|
Packit |
577717 |
atomic_set(&amd_mc_init_data->non0core_seen, 1);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
/* We rely on cpu_set() being atomic! */
|
|
Packit |
577717 |
cpu_set(cpu, amd_mc_init_data->core0_mask);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init amd_multicore_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct amd_mc_init_data amd_mc_init_data;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
atomic_set(&amd_mc_init_data.non0core_seen, 0);
|
|
Packit |
577717 |
cpus_clear(amd_mc_init_data.core0_mask);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
smp_call_function(amd_mc_init_cpu, &amd_mc_init_data, 1);
|
|
Packit |
577717 |
amd_mc_init_cpu(&amd_mc_init_data);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (atomic_read(&amd_mc_init_data.non0core_seen) == 0) {
|
|
Packit |
577717 |
printk(KERN_INFO "%s: !non0core_seen\n", __FUNCTION__);
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#if 1 /* XXX: temporary sanity check, should be impossible */
|
|
Packit |
577717 |
if (cpus_empty(amd_mc_init_data.core0_mask)) {
|
|
Packit |
577717 |
printk(KERN_ERR "%s: Error: cpus_empty(core0_mask)\n", __FUNCTION__);
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
amd_is_multicore = 1;
|
|
Packit |
577717 |
if (current_cpu_data.x86 == 15 &&
|
|
Packit |
577717 |
current_cpu_data.x86_model >= 0x20 &&
|
|
Packit |
577717 |
current_cpu_data.x86_model < 0x40) {
|
|
Packit |
577717 |
amd_is_k8_mc_RevE = 1;
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr/x86.c: multi-core K8 RevE detected:"
|
|
Packit |
577717 |
" restricting access to northbridge events\n");
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
amd_mc_core0_mask = amd_mc_init_data.core0_mask;
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr/x86.c: multi-core AMDs detected:"
|
|
Packit |
577717 |
" forcing northbridge events to core0 CPUs\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#else /* CONFIG_SMP */
|
|
Packit |
577717 |
#define amd_multicore_init() (0)
|
|
Packit |
577717 |
#endif /* CONFIG_SMP */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init amd_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static char amd_name[] __initdata = "AMD K7/K8/Fam10h/Fam11h";
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!cpu_has_tsc)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
switch (current_cpu_data.x86) {
|
|
Packit |
577717 |
case 6: /* K7 */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_AMD_K7;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 15: /* K8. Like a K7 with a different event set. */
|
|
Packit |
577717 |
if ((current_cpu_data.x86_model > 5) ||
|
|
Packit |
577717 |
(current_cpu_data.x86_model >= 4 && current_cpu_data.x86_mask >= 8)) {
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_AMD_K8C;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_AMD_K8;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (amd_multicore_init() < 0)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 16:
|
|
Packit |
577717 |
case 17:
|
|
Packit |
577717 |
is_fam10h = 1;
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_AMD_FAM10H;
|
|
Packit |
577717 |
if (amd_multicore_init() < 0)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_AMD);
|
|
Packit |
577717 |
perfctr_cpu_name = amd_name;
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
write_control = k7_write_control;
|
|
Packit |
577717 |
check_control = k7_check_control;
|
|
Packit |
577717 |
pmu_msrs = &k7_pmu_msrs;
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
if (cpu_has_apic) {
|
|
Packit |
577717 |
perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
|
|
Packit |
577717 |
cpu_isuspend = k7_isuspend;
|
|
Packit |
577717 |
cpu_iresume = k7_iresume;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init cyrix_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static char mii_name[] __initdata = "Cyrix 6x86MX/MII/III";
|
|
Packit |
577717 |
if (!cpu_has_tsc)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
switch (current_cpu_data.x86) {
|
|
Packit |
577717 |
case 6: /* 6x86MX, MII, or III */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_CYRIX_MII;
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_P5);
|
|
Packit |
577717 |
perfctr_cpu_name = mii_name;
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
write_control = p5_write_control;
|
|
Packit |
577717 |
check_control = mii_check_control;
|
|
Packit |
577717 |
pmu_msrs = &p5_pmu_msrs;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init centaur_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#if !defined(CONFIG_X86_TSC)
|
|
Packit |
577717 |
static char winchip_name[] __initdata = "WinChip C6/2/3";
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
static char vc3_name[] __initdata = "VIA C3";
|
|
Packit |
577717 |
switch (current_cpu_data.x86) {
|
|
Packit |
577717 |
#if !defined(CONFIG_X86_TSC)
|
|
Packit |
577717 |
case 5:
|
|
Packit |
577717 |
switch (current_cpu_data.x86_model) {
|
|
Packit |
577717 |
case 4: /* WinChip C6 */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_WINCHIP_C6;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 8: /* WinChip 2, 2A, or 2B */
|
|
Packit |
577717 |
case 9: /* WinChip 3, a 2A with larger cache and lower voltage */
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_WINCHIP_2;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_WINCHIP);
|
|
Packit |
577717 |
perfctr_cpu_name = winchip_name;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* TSC must be inaccessible for perfctrs to work.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (!(read_cr4() & X86_CR4_TSD) || cpu_has_tsc)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDTSC;
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
write_control = c6_write_control;
|
|
Packit |
577717 |
check_control = c6_check_control;
|
|
Packit |
577717 |
pmu_msrs = &p5_pmu_msrs;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
#endif /* !CONFIG_X86_TSC */
|
|
Packit |
577717 |
case 6: /* VIA C3 */
|
|
Packit |
577717 |
if (!cpu_has_tsc)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
switch (current_cpu_data.x86_model) {
|
|
Packit |
577717 |
case 6: /* Cyrix III */
|
|
Packit |
577717 |
case 7: /* Samuel 2, Ezra (steppings >= 8) */
|
|
Packit |
577717 |
case 8: /* Ezra-T */
|
|
Packit |
577717 |
case 9: /* Antaur/Nehemiah */
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_VIA_C3;
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_VC3);
|
|
Packit |
577717 |
perfctr_cpu_name = vc3_name;
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
write_control = p6_write_control;
|
|
Packit |
577717 |
check_control = vc3_check_control;
|
|
Packit |
577717 |
pmu_msrs = &vc3_pmu_msrs;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int __init generic_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static char generic_name[] __initdata = "Generic x86 with TSC";
|
|
Packit |
577717 |
if (!cpu_has_tsc)
|
|
Packit |
577717 |
return -ENODEV;
|
|
Packit |
577717 |
perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
|
|
Packit |
577717 |
perfctr_info.cpu_type = PERFCTR_X86_GENERIC;
|
|
Packit |
577717 |
perfctr_set_tests_type(PTT_GENERIC);
|
|
Packit |
577717 |
perfctr_cpu_name = generic_name;
|
|
Packit |
577717 |
check_control = generic_check_control;
|
|
Packit |
577717 |
write_control = p6_write_control;
|
|
Packit |
577717 |
read_counters = rdpmc_read_counters;
|
|
Packit |
577717 |
pmu_msrs = NULL;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_cpu_invalidate_cache(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
struct per_cpu_cache *cache = get_cpu_cache();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* per_cpu_cache[] is initialised to contain "impossible"
|
|
Packit |
577717 |
* evntsel values guaranteed to differ from anything accepted
|
|
Packit |
577717 |
* by perfctr_cpu_update_control().
|
|
Packit |
577717 |
* All-bits-one works for all currently supported processors.
|
|
Packit |
577717 |
* The memset also sets the ids to -1, which is intentional.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
memset(cache, ~0, sizeof(struct per_cpu_cache));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* To ensure that MSR_CORE_PERF_FIXED_CTR_CTRL is not written
|
|
Packit |
577717 |
* to on processors that do not have it, each CPU cache must
|
|
Packit |
577717 |
* indicate that it has an all-bits-zero value.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
cache->core2_fixed_ctr_ctrl = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* To ensure that MSR_OFFCORE_RSP[0..1] are not written to
|
|
Packit |
577717 |
* on processors that do not have them, each CPU cache must
|
|
Packit |
577717 |
* indicate that they have all-bits-zero values.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
cache->nhlm_offcore_rsp[0] = 0;
|
|
Packit |
577717 |
cache->nhlm_offcore_rsp[1] = 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_cpu_init_one(void *ignore)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* PREEMPT note: when called via smp_call_function(),
|
|
Packit |
577717 |
this is in IRQ context with preemption disabled. */
|
|
Packit |
577717 |
perfctr_cpu_clear_counters(1);
|
|
Packit |
577717 |
perfctr_cpu_invalidate_cache();
|
|
Packit |
577717 |
if (cpu_has_apic)
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
|
|
Packit |
577717 |
if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
|
|
Packit |
577717 |
set_in_cr4_local(X86_CR4_PCE);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_cpu_exit_one(void *ignore)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* PREEMPT note: when called via smp_call_function(),
|
|
Packit |
577717 |
this is in IRQ context with preemption disabled. */
|
|
Packit |
577717 |
perfctr_cpu_clear_counters(0);
|
|
Packit |
577717 |
perfctr_cpu_invalidate_cache();
|
|
Packit |
577717 |
if (cpu_has_apic)
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, APIC_DM_NMI | APIC_LVT_MASKED);
|
|
Packit |
577717 |
if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
|
|
Packit |
577717 |
clear_in_cr4_local(X86_CR4_PCE);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_pm_suspend(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* XXX: clear control registers */
|
|
Packit |
577717 |
printk("perfctr/x86: PM suspend\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_pm_resume(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* XXX: reload control registers */
|
|
Packit |
577717 |
printk("perfctr/x86: PM resume\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include <linux/sysdev.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
|
|
Packit |
577717 |
typedef pm_message_t perfctr_suspend_state_t;
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
typedef u32 perfctr_suspend_state_t;
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int perfctr_device_suspend(struct sys_device *dev,
|
|
Packit |
577717 |
perfctr_suspend_state_t state)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perfctr_pm_suspend();
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int perfctr_device_resume(struct sys_device *dev)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perfctr_pm_resume();
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct sysdev_class perfctr_sysclass = {
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
|
|
Packit |
577717 |
.name = "perfctr",
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
set_kset_name("perfctr"),
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
.resume = perfctr_device_resume,
|
|
Packit |
577717 |
.suspend = perfctr_device_suspend,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct sys_device device_perfctr = {
|
|
Packit |
577717 |
.id = 0,
|
|
Packit |
577717 |
.cls = &perfctr_sysclass,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void x86_pm_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (sysdev_class_register(&perfctr_sysclass) == 0)
|
|
Packit |
577717 |
sysdev_register(&device_perfctr);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void x86_pm_exit(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
sysdev_unregister(&device_perfctr);
|
|
Packit |
577717 |
sysdev_class_unregister(&perfctr_sysclass);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#else /* CONFIG_X86_LOCAL_APIC && CONFIG_PM */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void x86_pm_init(void) { }
|
|
Packit |
577717 |
static inline void x86_pm_exit(void) { }
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC && CONFIG_PM */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
|
|
Packit |
577717 |
static int reserve_lapic_nmi(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret = 0;
|
|
Packit |
577717 |
if (nmi_perfctr_msr) {
|
|
Packit |
577717 |
nmi_perfctr_msr = 0;
|
|
Packit |
577717 |
disable_lapic_nmi_watchdog();
|
|
Packit |
577717 |
ret = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void release_lapic_nmi(void) { }
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_release_perfctr_range(unsigned int first_msr, unsigned int nr_msrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i = 0; i < nr_msrs; ++i)
|
|
Packit |
577717 |
release_perfctr_nmi(first_msr + i);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int perfctr_reserve_perfctr_range(unsigned int first_msr, unsigned int nr_msrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i = 0; i < nr_msrs; ++i)
|
|
Packit |
577717 |
if (!reserve_perfctr_nmi(first_msr + i)) {
|
|
Packit |
577717 |
printk(KERN_ERR "perfctr/x86.c: failed to reserve perfctr MSR %#x\n",
|
|
Packit |
577717 |
first_msr + i);
|
|
Packit |
577717 |
perfctr_release_perfctr_range(first_msr, i);
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_release_evntsel_range(unsigned int first_msr, unsigned int nr_msrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i = 0; i < nr_msrs; ++i)
|
|
Packit |
577717 |
release_evntsel_nmi(first_msr + i);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int perfctr_reserve_evntsel_range(unsigned int first_msr, unsigned int nr_msrs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i = 0; i < nr_msrs; ++i)
|
|
Packit |
577717 |
if (!reserve_evntsel_nmi(first_msr + i)) {
|
|
Packit |
577717 |
printk(KERN_ERR "perfctr/x86.c: failed to reserve evntsel MSR %#x\n",
|
|
Packit |
577717 |
first_msr + i);
|
|
Packit |
577717 |
perfctr_release_evntsel_range(first_msr, i);
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_release_counters_cpu(void *ignore)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const struct perfctr_pmu_msrs *pmu;
|
|
Packit |
577717 |
const struct perfctr_msr_range *msrs;
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmu = pmu_msrs;
|
|
Packit |
577717 |
if (!pmu)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
msrs = pmu->perfctrs;
|
|
Packit |
577717 |
if (msrs)
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
perfctr_release_perfctr_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
msrs = pmu->evntsels;
|
|
Packit |
577717 |
if (msrs)
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
perfctr_release_evntsel_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_release_counters(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
|
Packit |
577717 |
perfctr_release_counters_cpu(NULL);
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
on_each_cpu(perfctr_release_counters_cpu, NULL, 1);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void perfctr_reserve_counters_cpu(void *error)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const struct perfctr_pmu_msrs *pmu;
|
|
Packit |
577717 |
const struct perfctr_msr_range *msrs;
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pmu = pmu_msrs;
|
|
Packit |
577717 |
if (!pmu)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
msrs = pmu->perfctrs;
|
|
Packit |
577717 |
if (msrs) {
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
if (perfctr_reserve_perfctr_range(msrs[i].first_msr, msrs[i].nr_msrs))
|
|
Packit |
577717 |
goto err_perfctrs;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
msrs = pmu->evntsels;
|
|
Packit |
577717 |
if (msrs) {
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
if (perfctr_reserve_evntsel_range(msrs[i].first_msr, msrs[i].nr_msrs))
|
|
Packit |
577717 |
goto err_evntsels;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
err_evntsels:
|
|
Packit |
577717 |
while (--i >= 0)
|
|
Packit |
577717 |
perfctr_release_evntsel_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
msrs = pmu->perfctrs;
|
|
Packit |
577717 |
if (!msrs)
|
|
Packit |
577717 |
goto err;
|
|
Packit |
577717 |
for(i = 0; msrs[i].first_msr; ++i)
|
|
Packit |
577717 |
;
|
|
Packit |
577717 |
err_perfctrs:
|
|
Packit |
577717 |
while (--i >= 0)
|
|
Packit |
577717 |
perfctr_release_perfctr_range(msrs[i].first_msr, msrs[i].nr_msrs);
|
|
Packit |
577717 |
err:
|
|
Packit |
577717 |
atomic_set((atomic_t*)error, -1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int perfctr_reserve_counters(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
atomic_t error = ATOMIC_INIT(0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
|
Packit |
577717 |
perfctr_reserve_counters_cpu(&error);
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
on_each_cpu(perfctr_reserve_counters_cpu, &error, 1);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
return atomic_read(&error);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int reserve_lapic_nmi(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (nmi_watchdog != NMI_LOCAL_APIC)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
if (atomic_read(&nmi_active) <= 0)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
|
Packit |
577717 |
disable_lapic_nmi_watchdog();
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
on_each_cpu(stop_apic_nmi_watchdog, NULL, 1);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
return perfctr_reserve_counters();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void release_lapic_nmi(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perfctr_release_counters();
|
|
Packit |
577717 |
if (nmi_watchdog != NMI_LOCAL_APIC)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
if (atomic_read(&nmi_active) != 0)
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
|
Packit |
577717 |
enable_lapic_nmi_watchdog();
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
on_each_cpu(setup_apic_nmi_watchdog, NULL, 1);
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#else /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
static inline int reserve_lapic_nmi(void) { return 0; }
|
|
Packit |
577717 |
static inline void release_lapic_nmi(void) { }
|
|
Packit |
577717 |
#endif /* CONFIG_X86_LOCAL_APIC */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#ifdef CONFIG_PERFCTR_INIT_TESTS
|
|
Packit |
577717 |
if (reserve_lapic_nmi() >= 0) {
|
|
Packit |
577717 |
perfctr_x86_init_tests();
|
|
Packit |
577717 |
release_lapic_nmi();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int __init perfctr_cpu_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int err = -ENODEV;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
preempt_disable();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* RDPMC and RDTSC are on by default. They will be disabled
|
|
Packit |
577717 |
by the init procedures if necessary. */
|
|
Packit |
577717 |
perfctr_info.cpu_features = PERFCTR_FEATURE_RDPMC | PERFCTR_FEATURE_RDTSC;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cpu_has_msr) {
|
|
Packit |
577717 |
switch (current_cpu_data.x86_vendor) {
|
|
Packit |
577717 |
case X86_VENDOR_INTEL:
|
|
Packit |
577717 |
err = intel_init();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case X86_VENDOR_AMD:
|
|
Packit |
577717 |
err = amd_init();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case X86_VENDOR_CYRIX:
|
|
Packit |
577717 |
err = cyrix_init();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case X86_VENDOR_CENTAUR:
|
|
Packit |
577717 |
err = centaur_init();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (err) {
|
|
Packit |
577717 |
err = generic_init(); /* last resort */
|
|
Packit |
577717 |
if (err)
|
|
Packit |
577717 |
goto out;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
do_init_tests();
|
|
Packit |
577717 |
finalise_backpatching();
|
|
Packit |
577717 |
|
|
Packit |
577717 |
perfctr_info.cpu_khz = perfctr_cpu_khz();
|
|
Packit |
577717 |
perfctr_info.tsc_to_cpu_mult = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
out:
|
|
Packit |
577717 |
preempt_enable();
|
|
Packit |
577717 |
return err;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void __exit perfctr_cpu_exit(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/****************************************************************
|
|
Packit |
577717 |
* *
|
|
Packit |
577717 |
* Hardware reservation. *
|
|
Packit |
577717 |
* *
|
|
Packit |
577717 |
****************************************************************/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static DEFINE_MUTEX(mutex);
|
|
Packit |
577717 |
static const char *current_service = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
const char *perfctr_cpu_reserve(const char *service)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const char *ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
mutex_lock(&mutex);
|
|
Packit |
577717 |
ret = current_service;
|
|
Packit |
577717 |
if (ret)
|
|
Packit |
577717 |
goto out_unlock;
|
|
Packit |
577717 |
ret = "unknown driver (oprofile?)";
|
|
Packit |
577717 |
if (reserve_lapic_nmi() < 0)
|
|
Packit |
577717 |
goto out_unlock;
|
|
Packit |
577717 |
current_service = service;
|
|
Packit |
577717 |
__module_get(THIS_MODULE);
|
|
Packit |
577717 |
if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
|
|
Packit |
577717 |
mmu_cr4_features |= X86_CR4_PCE;
|
|
Packit |
577717 |
on_each_cpu(perfctr_cpu_init_one, NULL, 1);
|
|
Packit |
577717 |
perfctr_cpu_set_ihandler(NULL);
|
|
Packit |
577717 |
x86_pm_init();
|
|
Packit |
577717 |
ret = NULL;
|
|
Packit |
577717 |
out_unlock:
|
|
Packit |
577717 |
mutex_unlock(&mutex);
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void perfctr_cpu_release(const char *service)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
mutex_lock(&mutex);
|
|
Packit |
577717 |
if (service != current_service) {
|
|
Packit |
577717 |
printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
|
|
Packit |
577717 |
__FUNCTION__, service, current_service);
|
|
Packit |
577717 |
goto out_unlock;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* power down the counters */
|
|
Packit |
577717 |
if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
|
|
Packit |
577717 |
mmu_cr4_features &= ~X86_CR4_PCE;
|
|
Packit |
577717 |
on_each_cpu(perfctr_cpu_exit_one, NULL, 1);
|
|
Packit |
577717 |
perfctr_cpu_set_ihandler(NULL);
|
|
Packit |
577717 |
x86_pm_exit();
|
|
Packit |
577717 |
current_service = 0;
|
|
Packit |
577717 |
release_lapic_nmi();
|
|
Packit |
577717 |
module_put(THIS_MODULE);
|
|
Packit |
577717 |
out_unlock:
|
|
Packit |
577717 |
mutex_unlock(&mutex);
|
|
Packit |
577717 |
}
|