|
Packit |
577717 |
/* $Id: x86_tests.c,v 1.23.2.14 2007/10/07 17:18:32 mikpe Exp $
|
|
Packit |
577717 |
* Performance-monitoring counters driver.
|
|
Packit |
577717 |
* Optional x86/x86_64-specific init-time tests.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (C) 1999-2007 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 |
#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_CTR_CTRL
|
|
Packit |
577717 |
#undef MSR_P4_IQ_CCCR0
|
|
Packit |
577717 |
#undef MSR_P4_CRU_ESCR0
|
|
Packit |
577717 |
#include <asm/fixmap.h>
|
|
Packit |
577717 |
#include <asm/apic.h>
|
|
Packit |
577717 |
#include "x86_compat.h"
|
|
Packit |
577717 |
#include "x86_tests.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define MSR_P5_CESR 0x11
|
|
Packit |
577717 |
#define MSR_P5_CTR0 0x12
|
|
Packit |
577717 |
#define P5_CESR_VAL (0x16 | (3<<6))
|
|
Packit |
577717 |
#define MSR_P6_PERFCTR0 0xC1
|
|
Packit |
577717 |
#define MSR_P6_EVNTSEL0 0x186
|
|
Packit |
577717 |
#define P6_EVNTSEL0_VAL (0xC0 | (3<<16) | (1<<22))
|
|
Packit |
577717 |
#define MSR_K7_EVNTSEL0 0xC0010000
|
|
Packit |
577717 |
#define MSR_K7_PERFCTR0 0xC0010004
|
|
Packit |
577717 |
#define K7_EVNTSEL0_VAL (0xC0 | (3<<16) | (1<<22))
|
|
Packit |
577717 |
#define VC3_EVNTSEL1_VAL 0xC0
|
|
Packit |
577717 |
#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x38D
|
|
Packit |
577717 |
#define CORE2_PMC_FIXED_CTR0 ((1<<30) | 0)
|
|
Packit |
577717 |
#define MSR_P4_IQ_COUNTER0 0x30C
|
|
Packit |
577717 |
#define MSR_P4_IQ_CCCR0 0x36C
|
|
Packit |
577717 |
#define MSR_P4_CRU_ESCR0 0x3B8
|
|
Packit |
577717 |
#define P4_CRU_ESCR0_VAL ((2<<25) | (1<<9) | (0x3<<2))
|
|
Packit |
577717 |
#define P4_IQ_CCCR0_VAL ((0x3<<16) | (4<<13) | (1<<12))
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define NITER 64
|
|
Packit |
577717 |
#define X2(S) S";"S
|
|
Packit |
577717 |
#define X8(S) X2(X2(X2(S)))
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef __x86_64__
|
|
Packit |
577717 |
#define CR4MOV "movq"
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
#define CR4MOV "movl"
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifndef CONFIG_X86_LOCAL_APIC
|
|
Packit |
577717 |
#undef apic_write
|
|
Packit |
577717 |
#define apic_write(reg,vector) do{}while(0)
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define rdtsc_low(low) \
|
|
Packit |
577717 |
__asm__ __volatile__("rdtsc" : "=a"(low) : : "edx")
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_rdpmc(unsigned pmc, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__(X8("rdpmc") : : "c"(pmc) : "eax", "edx");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_rdmsr(unsigned msr, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__(X8("rdmsr") : : "c"(msr) : "eax", "edx");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_wrmsr(unsigned msr, unsigned data)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__(X8("wrmsr") : : "c"(msr), "a"(data), "d"(0));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_rdcr4(unsigned unused1, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
unsigned long dummy;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__(X8(CR4MOV" %%cr4,%0") : "=r"(dummy));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_wrcr4(unsigned cr4, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__(X8(CR4MOV" %0,%%cr4") : : "r"((long)cr4));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_rdtsc(unsigned unused1, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__(X8("rdtsc") : : : "eax", "edx");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_wrlvtpc(unsigned val, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i) {
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
apic_write(APIC_LVTPC, val);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_sync_core(unsigned unused1, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i) {
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init do_empty_loop(unsigned unused1, unsigned unused2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned i;
|
|
Packit |
577717 |
for(i = 0; i < NITER/8; ++i)
|
|
Packit |
577717 |
__asm__ __volatile__("" : : "c"(0));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned __init run(void (*doit)(unsigned, unsigned),
|
|
Packit |
577717 |
unsigned arg1, unsigned arg2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned start, stop;
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
rdtsc_low(start);
|
|
Packit |
577717 |
(*doit)(arg1, arg2); /* should take < 2^32 cycles to complete */
|
|
Packit |
577717 |
sync_core();
|
|
Packit |
577717 |
rdtsc_low(stop);
|
|
Packit |
577717 |
return stop - start;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init init_tests_message(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
printk(KERN_INFO "Please email the following PERFCTR INIT lines "
|
|
Packit |
577717 |
"to mikpe@it.uu.se\n"
|
|
Packit |
577717 |
KERN_INFO "To remove this message, rebuild the driver "
|
|
Packit |
577717 |
"with CONFIG_PERFCTR_INIT_TESTS=n\n");
|
|
Packit |
577717 |
printk(KERN_INFO "PERFCTR INIT: vendor %u, family %u, model %u, stepping %u, clock %u kHz\n",
|
|
Packit |
577717 |
current_cpu_data.x86_vendor,
|
|
Packit |
577717 |
current_cpu_data.x86,
|
|
Packit |
577717 |
current_cpu_data.x86_model,
|
|
Packit |
577717 |
current_cpu_data.x86_mask,
|
|
Packit |
577717 |
perfctr_cpu_khz());
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init
|
|
Packit |
577717 |
measure_overheads(unsigned msr_evntsel0, unsigned evntsel0, unsigned msr_perfctr0,
|
|
Packit |
577717 |
unsigned msr_cccr, unsigned cccr_val, unsigned is_core2)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
unsigned int loop, ticks[15];
|
|
Packit |
577717 |
const char *name[15];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (msr_evntsel0)
|
|
Packit |
577717 |
wrmsr(msr_evntsel0, 0, 0);
|
|
Packit |
577717 |
if (msr_cccr)
|
|
Packit |
577717 |
wrmsr(msr_cccr, 0, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
name[0] = "rdtsc";
|
|
Packit |
577717 |
ticks[0] = run(do_rdtsc, 0, 0);
|
|
Packit |
577717 |
name[1] = "rdpmc";
|
|
Packit |
577717 |
ticks[1] = (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
|
|
Packit |
577717 |
? run(do_rdpmc,1,0) : 0;
|
|
Packit |
577717 |
name[2] = "rdmsr (counter)";
|
|
Packit |
577717 |
ticks[2] = msr_perfctr0 ? run(do_rdmsr, msr_perfctr0, 0) : 0;
|
|
Packit |
577717 |
name[3] = msr_cccr ? "rdmsr (escr)" : "rdmsr (evntsel)";
|
|
Packit |
577717 |
ticks[3] = msr_evntsel0 ? run(do_rdmsr, msr_evntsel0, 0) : 0;
|
|
Packit |
577717 |
name[4] = "wrmsr (counter)";
|
|
Packit |
577717 |
ticks[4] = msr_perfctr0 ? run(do_wrmsr, msr_perfctr0, 0) : 0;
|
|
Packit |
577717 |
name[5] = msr_cccr ? "wrmsr (escr)" : "wrmsr (evntsel)";
|
|
Packit |
577717 |
ticks[5] = msr_evntsel0 ? run(do_wrmsr, msr_evntsel0, evntsel0) : 0;
|
|
Packit |
577717 |
name[6] = "read cr4";
|
|
Packit |
577717 |
ticks[6] = run(do_rdcr4, 0, 0);
|
|
Packit |
577717 |
name[7] = "write cr4";
|
|
Packit |
577717 |
ticks[7] = run(do_wrcr4, read_cr4(), 0);
|
|
Packit |
577717 |
name[8] = "rdpmc (fast)";
|
|
Packit |
577717 |
ticks[8] = msr_cccr ? run(do_rdpmc, 0x80000001, 0) : 0;
|
|
Packit |
577717 |
name[9] = "rdmsr (cccr)";
|
|
Packit |
577717 |
ticks[9] = msr_cccr ? run(do_rdmsr, msr_cccr, 0) : 0;
|
|
Packit |
577717 |
name[10] = "wrmsr (cccr)";
|
|
Packit |
577717 |
ticks[10] = msr_cccr ? run(do_wrmsr, msr_cccr, cccr_val) : 0;
|
|
Packit |
577717 |
name[11] = "write LVTPC";
|
|
Packit |
577717 |
ticks[11] = (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
|
|
Packit |
577717 |
? run(do_wrlvtpc, APIC_DM_NMI|APIC_LVT_MASKED, 0) : 0;
|
|
Packit |
577717 |
name[12] = "sync_core";
|
|
Packit |
577717 |
ticks[12] = run(do_sync_core, 0, 0);
|
|
Packit |
577717 |
name[13] = "read fixed_ctr0";
|
|
Packit |
577717 |
ticks[13] = is_core2 ? run(do_rdpmc, CORE2_PMC_FIXED_CTR0, 0) : 0;
|
|
Packit |
577717 |
name[14] = "wrmsr fixed_ctr_ctrl";
|
|
Packit |
577717 |
ticks[14] = is_core2 ? run(do_wrmsr, MSR_CORE_PERF_FIXED_CTR_CTRL, 0) : 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
loop = run(do_empty_loop, 0, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (msr_evntsel0)
|
|
Packit |
577717 |
wrmsr(msr_evntsel0, 0, 0);
|
|
Packit |
577717 |
if (msr_cccr)
|
|
Packit |
577717 |
wrmsr(msr_cccr, 0, 0);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
init_tests_message();
|
|
Packit |
577717 |
printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER);
|
|
Packit |
577717 |
printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop);
|
|
Packit |
577717 |
for(i = 0; i < ARRAY_SIZE(ticks); ++i) {
|
|
Packit |
577717 |
unsigned int x;
|
|
Packit |
577717 |
if (!ticks[i])
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
x = ((ticks[i] - loop) * 10) / NITER;
|
|
Packit |
577717 |
printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n",
|
|
Packit |
577717 |
name[i], x/10, x%10, ticks[i]);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifndef __x86_64__
|
|
Packit |
577717 |
static inline void perfctr_p5_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(MSR_P5_CESR, P5_CESR_VAL, MSR_P5_CTR0, 0, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if !defined(CONFIG_X86_TSC)
|
|
Packit |
577717 |
static inline void perfctr_c6_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int cesr, dummy;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
rdmsr(MSR_P5_CESR, cesr, dummy);
|
|
Packit |
577717 |
init_tests_message();
|
|
Packit |
577717 |
printk(KERN_INFO "PERFCTR INIT: boot CESR == %#08x\n", cesr);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_vc3_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(MSR_P6_EVNTSEL0+1, VC3_EVNTSEL1_VAL, MSR_P6_PERFCTR0+1, 0, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif /* !__x86_64__ */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_p6_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(MSR_P6_EVNTSEL0, P6_EVNTSEL0_VAL, MSR_P6_PERFCTR0, 0, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_core2_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(MSR_P6_EVNTSEL0, P6_EVNTSEL0_VAL, MSR_P6_PERFCTR0, 0, 0, 1);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_p4_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(MSR_P4_CRU_ESCR0, P4_CRU_ESCR0_VAL, MSR_P4_IQ_COUNTER0,
|
|
Packit |
577717 |
MSR_P4_IQ_CCCR0, P4_IQ_CCCR0_VAL, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_k7_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(MSR_K7_EVNTSEL0, K7_EVNTSEL0_VAL, MSR_K7_PERFCTR0, 0, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void perfctr_generic_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
measure_overheads(0, 0, 0, 0, 0, 0);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
enum perfctr_x86_tests_type perfctr_x86_tests_type __initdata = PTT_UNKNOWN;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void __init perfctr_x86_init_tests(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
switch (perfctr_x86_tests_type) {
|
|
Packit |
577717 |
#ifndef __x86_64__
|
|
Packit |
577717 |
case PTT_P5: /* Intel P5, P5MMX; Cyrix 6x86MX, MII, III */
|
|
Packit |
577717 |
perfctr_p5_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
#if !defined(CONFIG_X86_TSC)
|
|
Packit |
577717 |
case PTT_WINCHIP: /* WinChip C6, 2, 3 */
|
|
Packit |
577717 |
perfctr_c6_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
case PTT_VC3: /* VIA C3 */
|
|
Packit |
577717 |
perfctr_vc3_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
#endif /* !__x86_64__ */
|
|
Packit |
577717 |
case PTT_P6: /* Intel PPro, PII, PIII, PENTM, CORE */
|
|
Packit |
577717 |
perfctr_p6_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PTT_CORE2: /* Intel Core 2 */
|
|
Packit |
577717 |
perfctr_core2_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PTT_P4: /* Intel P4 */
|
|
Packit |
577717 |
perfctr_p4_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PTT_AMD: /* AMD K7, K8 */
|
|
Packit |
577717 |
perfctr_k7_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PTT_GENERIC:
|
|
Packit |
577717 |
perfctr_generic_init_tests();
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
printk(KERN_INFO "%s: unknown CPU type %u\n",
|
|
Packit |
577717 |
__FUNCTION__, perfctr_x86_tests_type);
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|