/**
* @file op_model_p4.c
* P4 model-specific MSR operations
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Graydon Hoare
*/
#include <xen/types.h>
#include <asm/msr.h>
#include <asm/io.h>
#include <asm/apic.h>
#include <asm/processor.h>
#include <xen/sched.h>
#include <asm/regs.h>
#include <asm/current.h>
#include "op_x86_model.h"
#include "op_counter.h"
#define NUM_EVENTS 39
#define NUM_COUNTERS_NON_HT 8
#define NUM_ESCRS_NON_HT 45
#define NUM_CCCRS_NON_HT 18
#define NUM_CONTROLS_NON_HT (NUM_ESCRS_NON_HT + NUM_CCCRS_NON_HT)
#define NUM_COUNTERS_HT2 4
#define NUM_ESCRS_HT2 23
#define NUM_CCCRS_HT2 9
#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
static unsigned int num_counters = NUM_COUNTERS_NON_HT;
/* this has to be checked dynamically since the
hyper-threadedness of a chip is discovered at
kernel boot-time. */
static inline void setup_num_counters(void)
{
#ifdef CONFIG_SMP
if (boot_cpu_data.x86_num_siblings == 2) /* XXX */
num_counters = NUM_COUNTERS_HT2;
#endif
}
static int inline addr_increment(void)
{
#ifdef CONFIG_SMP
return boot_cpu_data.x86_num_siblings == 2 ? 2 : 1;
#else
return 1;
#endif
}
/* tables to simulate simplified hardware view of p4 registers */
struct p4_counter_binding {
int virt_counter;
int counter_address;
int cccr_address;
};
struct p4_event_binding {
int escr_select; /* value to put in CCCR */
int event_select; /* value to put in ESCR */
struct {
int virt_counter; /* for this counter... */
int escr_address; /* use this ESCR */
} bindings[2];
};
/* nb: these CTR_* defines are a duplicate of defines in
event/i386.p4*events. */
#define CTR_BPU_0 (1 << 0)
#define CTR_MS_0 (1 << 1)
#define CTR_FLAME_0 (1 << 2)
#define CTR_IQ_4 (1 << 3)
#define CTR_BPU_2 (1 << 4)
#define CTR_MS_2 (1 << 5)
#define CTR_FLAME_2 (1 << 6)
#define CTR_IQ_5 (1 << 7)
static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
{ CTR_BPU_0, MSR_P4_BPU_PERFCTR0, MSR_P4_BPU_CCCR0 },
{ CTR_MS_0, MSR_P4_MS_PERFCTR0, MSR_P4_MS_CCCR0 },
{ CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
{ CTR_IQ_4, MSR_P4_IQ_PERFCTR4, MSR_P4_IQ_CCCR4 },
{ CTR_BPU_2, MSR_P4_BPU_PERFCTR2, MSR_P4_BPU_CCCR2 },
{ CTR_MS_2, MSR_P4_MS_PERFCTR2, MSR_P4_MS_CCCR2 },
{ CTR_FLAME_2, MSR_P4_FLAME_PERFCTR2, MSR_P4_FLAME_CCCR2 },
{ CTR_IQ_5, MSR_P4_IQ_PERFCTR5, MSR_P4_IQ_CCCR5 }
};
#define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
/* All cccr we don't use. */
static int p4_unused_cccr[NUM_UNUSED_CCCRS] = {
MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3,
MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3,
MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3,
MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR1,
MSR_P4_IQ_CCCR2, MSR_P4_IQ_CCCR3
};
/* p4 event codes in libop/op_event.h are indices into this table. */
static struct p4_event_binding p4_events[NUM_EVENTS] = {
{ /* BRANCH_RETIRED */
0x05, 0x06,
{ {CTR_IQ_4, MSR_P4_CRU_ESCR2},
{CTR_IQ_5, MSR_P4_CRU_ESCR3} }
},
{ /* MISPRED_BRANCH_RETIRED */
0x04, 0x03,
{ { CTR_IQ_4, MSR_P4_CRU_ESCR0},
{ CTR_IQ_5, MSR_P4_CRU_ESCR1} }
},
{ /* TC_DELIVER_MODE */
0x01, 0x01,
{ { CTR_MS_0, MSR_P4_TC_ESCR0},
{ CTR_MS_2, MSR_P4_TC_ESCR1} }
},
{ /* BPU_FETCH_REQUEST */
0x00, 0x03,
{ { CTR_BPU_0, MSR_P4_BPU_ESCR0},