Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9356c53 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'oprofile-for-linus' of...

Merge branch 'oprofile-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'oprofile-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (55 commits)
  arch/x86/oprofile/op_model_amd.c: fix op_amd_handle_ibs() return type
  Revert "x86: oprofile/op_model_amd.c set return values for op_amd_handle_ibs()"
  x86/oprofile: Small coding style fixes
  x86/oprofile: Add counter reservation check for virtual counters
  x86/oprofile: Implement op_x86_virt_to_phys()
  oprofile: Adding switch counter to oprofile statistic variables
  x86/oprofile: Implement mux_clone()
  x86/oprofile: Enable multiplexing only if the model supports it
  x86/oprofile: Add function has_mux() to check multiplexing support
  x86/oprofile: Modify initialization of num_virt_counters
  x86/oprofile: Remove unused num_virt_controls from struct op_x86_model_spec
  x86/oprofile: Remove const qualifier from struct op_x86_model_spec
  x86/oprofile: Moving nmi_cpu_switch() in nmi_int.c
  x86/oprofile: Moving nmi_cpu_save/restore_mpx_registers() in nmi_int.c
  x86/oprofile: Moving nmi_setup_cpu_mux() in nmi_int.c
  x86/oprofile: Implement multiplexing setup/shutdown functions
  oprofile: Grouping multiplexing code in op_model_amd.c
  oprofile: Introduce op_x86_phys_to_virt()
  oprofile: Grouping multiplexing code in oprof.c
  oprofile: Remove oprofile_multiplexing_init()
  ...
parents d90a7e86 4680e64a
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -30,6 +30,18 @@ config OPROFILE_IBS

	  If unsure, say N.

config OPROFILE_EVENT_MULTIPLEX
	bool "OProfile multiplexing support (EXPERIMENTAL)"
	default n
	depends on OPROFILE && X86
	help
	  The number of hardware counters is limited. The multiplexing
	  feature enables OProfile to gather more events than counters
	  are provided by the hardware. This is realized by switching
	  between events at an user specified time interval.

	  If unsure, say N.

config HAVE_OPROFILE
	bool

+288 −116
Original line number Diff line number Diff line
/**
 * @file nmi_int.c
 *
 * @remark Copyright 2002-2008 OProfile authors
 * @remark Copyright 2002-2009 OProfile authors
 * @remark Read the file COPYING
 *
 * @author John Levon <levon@movementarian.org>
 * @author Robert Richter <robert.richter@amd.com>
 * @author Barry Kasindorf <barry.kasindorf@amd.com>
 * @author Jason Yeh <jason.yeh@amd.com>
 * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
 */

#include <linux/init.h>
@@ -24,13 +27,35 @@
#include "op_counter.h"
#include "op_x86_model.h"

static struct op_x86_model_spec const *model;
static struct op_x86_model_spec *model;
static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
static DEFINE_PER_CPU(unsigned long, saved_lvtpc);

/* 0 == registered but off, 1 == registered and on */
static int nmi_enabled = 0;

struct op_counter_config counter_config[OP_MAX_COUNTER];

/* common functions */

u64 op_x86_get_ctrl(struct op_x86_model_spec const *model,
		    struct op_counter_config *counter_config)
{
	u64 val = 0;
	u16 event = (u16)counter_config->event;

	val |= ARCH_PERFMON_EVENTSEL_INT;
	val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0;
	val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0;
	val |= (counter_config->unit_mask & 0xFF) << 8;
	event &= model->event_mask ? model->event_mask : 0xFF;
	val |= event & 0xFF;
	val |= (event & 0x0F00) << 24;

	return val;
}


static int profile_exceptions_notify(struct notifier_block *self,
				     unsigned long val, void *data)
{
@@ -52,36 +77,214 @@ static int profile_exceptions_notify(struct notifier_block *self,

static void nmi_cpu_save_registers(struct op_msrs *msrs)
{
	unsigned int const nr_ctrs = model->num_counters;
	unsigned int const nr_ctrls = model->num_controls;
	struct op_msr *counters = msrs->counters;
	struct op_msr *controls = msrs->controls;
	unsigned int i;

	for (i = 0; i < nr_ctrs; ++i) {
		if (counters[i].addr) {
			rdmsr(counters[i].addr,
				counters[i].saved.low,
				counters[i].saved.high);
	for (i = 0; i < model->num_counters; ++i) {
		if (counters[i].addr)
			rdmsrl(counters[i].addr, counters[i].saved);
	}

	for (i = 0; i < model->num_controls; ++i) {
		if (controls[i].addr)
			rdmsrl(controls[i].addr, controls[i].saved);
	}
}

static void nmi_cpu_start(void *dummy)
{
	struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
	model->start(msrs);
}

static int nmi_start(void)
{
	on_each_cpu(nmi_cpu_start, NULL, 1);
	return 0;
}

static void nmi_cpu_stop(void *dummy)
{
	struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
	model->stop(msrs);
}

static void nmi_stop(void)
{
	on_each_cpu(nmi_cpu_stop, NULL, 1);
}

#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX

static DEFINE_PER_CPU(int, switch_index);

static inline int has_mux(void)
{
	return !!model->switch_ctrl;
}

inline int op_x86_phys_to_virt(int phys)
{
	return __get_cpu_var(switch_index) + phys;
}

inline int op_x86_virt_to_phys(int virt)
{
	return virt % model->num_counters;
}

static void nmi_shutdown_mux(void)
{
	int i;

	if (!has_mux())
		return;

	for_each_possible_cpu(i) {
		kfree(per_cpu(cpu_msrs, i).multiplex);
		per_cpu(cpu_msrs, i).multiplex = NULL;
		per_cpu(switch_index, i) = 0;
	}
}

static int nmi_setup_mux(void)
{
	size_t multiplex_size =
		sizeof(struct op_msr) * model->num_virt_counters;
	int i;

	if (!has_mux())
		return 1;

	for_each_possible_cpu(i) {
		per_cpu(cpu_msrs, i).multiplex =
			kmalloc(multiplex_size, GFP_KERNEL);
		if (!per_cpu(cpu_msrs, i).multiplex)
			return 0;
	}

	return 1;
}

static void nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs)
{
	int i;
	struct op_msr *multiplex = msrs->multiplex;

	if (!has_mux())
		return;

	for (i = 0; i < model->num_virt_counters; ++i) {
		if (counter_config[i].enabled) {
			multiplex[i].saved = -(u64)counter_config[i].count;
		} else {
			multiplex[i].addr  = 0;
			multiplex[i].saved = 0;
		}
	}

	for (i = 0; i < nr_ctrls; ++i) {
		if (controls[i].addr) {
			rdmsr(controls[i].addr,
				controls[i].saved.low,
				controls[i].saved.high);
	per_cpu(switch_index, cpu) = 0;
}

static void nmi_cpu_save_mpx_registers(struct op_msrs *msrs)
{
	struct op_msr *multiplex = msrs->multiplex;
	int i;

	for (i = 0; i < model->num_counters; ++i) {
		int virt = op_x86_phys_to_virt(i);
		if (multiplex[virt].addr)
			rdmsrl(multiplex[virt].addr, multiplex[virt].saved);
	}
}

static void nmi_save_registers(void *dummy)
static void nmi_cpu_restore_mpx_registers(struct op_msrs *msrs)
{
	struct op_msr *multiplex = msrs->multiplex;
	int i;

	for (i = 0; i < model->num_counters; ++i) {
		int virt = op_x86_phys_to_virt(i);
		if (multiplex[virt].addr)
			wrmsrl(multiplex[virt].addr, multiplex[virt].saved);
	}
}

static void nmi_cpu_switch(void *dummy)
{
	int cpu = smp_processor_id();
	int si = per_cpu(switch_index, cpu);
	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
	nmi_cpu_save_registers(msrs);

	nmi_cpu_stop(NULL);
	nmi_cpu_save_mpx_registers(msrs);

	/* move to next set */
	si += model->num_counters;
	if ((si > model->num_virt_counters) || (counter_config[si].count == 0))
		per_cpu(switch_index, cpu) = 0;
	else
		per_cpu(switch_index, cpu) = si;

	model->switch_ctrl(model, msrs);
	nmi_cpu_restore_mpx_registers(msrs);

	nmi_cpu_start(NULL);
}


/*
 * Quick check to see if multiplexing is necessary.
 * The check should be sufficient since counters are used
 * in ordre.
 */
static int nmi_multiplex_on(void)
{
	return counter_config[model->num_counters].count ? 0 : -EINVAL;
}

static int nmi_switch_event(void)
{
	if (!has_mux())
		return -ENOSYS;		/* not implemented */
	if (nmi_multiplex_on() < 0)
		return -EINVAL;		/* not necessary */

	on_each_cpu(nmi_cpu_switch, NULL, 1);

	return 0;
}

static inline void mux_init(struct oprofile_operations *ops)
{
	if (has_mux())
		ops->switch_events = nmi_switch_event;
}

static void mux_clone(int cpu)
{
	if (!has_mux())
		return;

	memcpy(per_cpu(cpu_msrs, cpu).multiplex,
	       per_cpu(cpu_msrs, 0).multiplex,
	       sizeof(struct op_msr) * model->num_virt_counters);
}

#else

inline int op_x86_phys_to_virt(int phys) { return phys; }
inline int op_x86_virt_to_phys(int virt) { return virt; }
static inline void nmi_shutdown_mux(void) { }
static inline int nmi_setup_mux(void) { return 1; }
static inline void
nmi_cpu_setup_mux(int cpu, struct op_msrs const * const msrs) { }
static inline void mux_init(struct oprofile_operations *ops) { }
static void mux_clone(int cpu) { }

#endif

static void free_msrs(void)
{
	int i;
@@ -95,7 +298,6 @@ static void free_msrs(void)

static int allocate_msrs(void)
{
	int success = 1;
	size_t controls_size = sizeof(struct op_msr) * model->num_controls;
	size_t counters_size = sizeof(struct op_msr) * model->num_counters;

@@ -103,30 +305,25 @@ static int allocate_msrs(void)
	for_each_possible_cpu(i) {
		per_cpu(cpu_msrs, i).counters = kmalloc(counters_size,
							GFP_KERNEL);
		if (!per_cpu(cpu_msrs, i).counters) {
			success = 0;
			break;
		}
		if (!per_cpu(cpu_msrs, i).counters)
			return 0;
		per_cpu(cpu_msrs, i).controls = kmalloc(controls_size,
							GFP_KERNEL);
		if (!per_cpu(cpu_msrs, i).controls) {
			success = 0;
			break;
		}
		if (!per_cpu(cpu_msrs, i).controls)
			return 0;
	}

	if (!success)
		free_msrs();

	return success;
	return 1;
}

static void nmi_cpu_setup(void *dummy)
{
	int cpu = smp_processor_id();
	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);
	nmi_cpu_save_registers(msrs);
	spin_lock(&oprofilefs_lock);
	model->setup_ctrs(msrs);
	model->setup_ctrs(model, msrs);
	nmi_cpu_setup_mux(cpu, msrs);
	spin_unlock(&oprofilefs_lock);
	per_cpu(saved_lvtpc, cpu) = apic_read(APIC_LVTPC);
	apic_write(APIC_LVTPC, APIC_DM_NMI);
@@ -144,11 +341,15 @@ static int nmi_setup(void)
	int cpu;

	if (!allocate_msrs())
		return -ENOMEM;

		err = -ENOMEM;
	else if (!nmi_setup_mux())
		err = -ENOMEM;
	else
		err = register_die_notifier(&profile_exceptions_nb);

	if (err) {
		free_msrs();
		nmi_shutdown_mux();
		return err;
	}

@@ -159,7 +360,9 @@ static int nmi_setup(void)
	/* Assume saved/restored counters are the same on all CPUs */
	model->fill_in_addresses(&per_cpu(cpu_msrs, 0));
	for_each_possible_cpu(cpu) {
		if (cpu != 0) {
		if (!cpu)
			continue;

		memcpy(per_cpu(cpu_msrs, cpu).counters,
		       per_cpu(cpu_msrs, 0).counters,
		       sizeof(struct op_msr) * model->num_counters);
@@ -167,37 +370,28 @@ static int nmi_setup(void)
		memcpy(per_cpu(cpu_msrs, cpu).controls,
		       per_cpu(cpu_msrs, 0).controls,
		       sizeof(struct op_msr) * model->num_controls);
		}

		mux_clone(cpu);
	}
	on_each_cpu(nmi_save_registers, NULL, 1);
	on_each_cpu(nmi_cpu_setup, NULL, 1);
	nmi_enabled = 1;
	return 0;
}

static void nmi_restore_registers(struct op_msrs *msrs)
static void nmi_cpu_restore_registers(struct op_msrs *msrs)
{
	unsigned int const nr_ctrs = model->num_counters;
	unsigned int const nr_ctrls = model->num_controls;
	struct op_msr *counters = msrs->counters;
	struct op_msr *controls = msrs->controls;
	unsigned int i;

	for (i = 0; i < nr_ctrls; ++i) {
		if (controls[i].addr) {
			wrmsr(controls[i].addr,
				controls[i].saved.low,
				controls[i].saved.high);
		}
	for (i = 0; i < model->num_controls; ++i) {
		if (controls[i].addr)
			wrmsrl(controls[i].addr, controls[i].saved);
	}

	for (i = 0; i < nr_ctrs; ++i) {
		if (counters[i].addr) {
			wrmsr(counters[i].addr,
				counters[i].saved.low,
				counters[i].saved.high);
		}
	for (i = 0; i < model->num_counters; ++i) {
		if (counters[i].addr)
			wrmsrl(counters[i].addr, counters[i].saved);
	}
}

@@ -205,7 +399,7 @@ static void nmi_cpu_shutdown(void *dummy)
{
	unsigned int v;
	int cpu = smp_processor_id();
	struct op_msrs *msrs = &__get_cpu_var(cpu_msrs);
	struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu);

	/* restoring APIC_LVTPC can trigger an apic error because the delivery
	 * mode and vector nr combination can be illegal. That's by design: on
@@ -216,7 +410,7 @@ static void nmi_cpu_shutdown(void *dummy)
	apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
	apic_write(APIC_LVTPC, per_cpu(saved_lvtpc, cpu));
	apic_write(APIC_LVTERR, v);
	nmi_restore_registers(msrs);
	nmi_cpu_restore_registers(msrs);
}

static void nmi_shutdown(void)
@@ -226,42 +420,18 @@ static void nmi_shutdown(void)
	nmi_enabled = 0;
	on_each_cpu(nmi_cpu_shutdown, NULL, 1);
	unregister_die_notifier(&profile_exceptions_nb);
	nmi_shutdown_mux();
	msrs = &get_cpu_var(cpu_msrs);
	model->shutdown(msrs);
	free_msrs();
	put_cpu_var(cpu_msrs);
}

static void nmi_cpu_start(void *dummy)
{
	struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
	model->start(msrs);
}

static int nmi_start(void)
{
	on_each_cpu(nmi_cpu_start, NULL, 1);
	return 0;
}

static void nmi_cpu_stop(void *dummy)
{
	struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs);
	model->stop(msrs);
}

static void nmi_stop(void)
{
	on_each_cpu(nmi_cpu_stop, NULL, 1);
}

struct op_counter_config counter_config[OP_MAX_COUNTER];

static int nmi_create_files(struct super_block *sb, struct dentry *root)
{
	unsigned int i;

	for (i = 0; i < model->num_counters; ++i) {
	for (i = 0; i < model->num_virt_counters; ++i) {
		struct dentry *dir;
		char buf[4];

@@ -270,7 +440,7 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root)
		 * NOTE:  assumes 1:1 mapping here (that counters are organized
		 *        sequentially in their struct assignment).
		 */
		if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i)))
		if (!avail_to_resrv_perfctr_nmi_bit(op_x86_virt_to_phys(i)))
			continue;

		snprintf(buf,  sizeof(buf), "%d", i);
@@ -402,6 +572,7 @@ module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0);
static int __init ppro_init(char **cpu_type)
{
	__u8 cpu_model = boot_cpu_data.x86_model;
	struct op_x86_model_spec *spec = &op_ppro_spec;	/* default */

	if (force_arch_perfmon && cpu_has_arch_perfmon)
		return 0;
@@ -428,7 +599,7 @@ static int __init ppro_init(char **cpu_type)
		*cpu_type = "i386/core_2";
		break;
	case 26:
		arch_perfmon_setup_counters();
		spec = &op_arch_perfmon_spec;
		*cpu_type = "i386/core_i7";
		break;
	case 28:
@@ -439,17 +610,7 @@ static int __init ppro_init(char **cpu_type)
		return 0;
	}

	model = &op_ppro_spec;
	return 1;
}

static int __init arch_perfmon_init(char **cpu_type)
{
	if (!cpu_has_arch_perfmon)
		return 0;
	*cpu_type = "i386/arch_perfmon";
	model = &op_arch_perfmon_spec;
	arch_perfmon_setup_counters();
	model = spec;
	return 1;
}

@@ -471,27 +632,26 @@ int __init op_nmi_init(struct oprofile_operations *ops)
		/* Needs to be at least an Athlon (or hammer in 32bit mode) */

		switch (family) {
		default:
			return -ENODEV;
		case 6:
			model = &op_amd_spec;
			cpu_type = "i386/athlon";
			break;
		case 0xf:
			model = &op_amd_spec;
			/* Actually it could be i386/hammer too, but give
			 user space an consistent name. */
			/*
			 * Actually it could be i386/hammer too, but
			 * give user space an consistent name.
			 */
			cpu_type = "x86-64/hammer";
			break;
		case 0x10:
			model = &op_amd_spec;
			cpu_type = "x86-64/family10";
			break;
		case 0x11:
			model = &op_amd_spec;
			cpu_type = "x86-64/family11h";
			break;
		default:
			return -ENODEV;
		}
		model = &op_amd_spec;
		break;

	case X86_VENDOR_INTEL:
@@ -510,8 +670,15 @@ int __init op_nmi_init(struct oprofile_operations *ops)
			break;
		}

		if (!cpu_type && !arch_perfmon_init(&cpu_type))
		if (cpu_type)
			break;

		if (!cpu_has_arch_perfmon)
			return -ENODEV;

		/* use arch perfmon as fallback */
		cpu_type = "i386/arch_perfmon";
		model = &op_arch_perfmon_spec;
		break;

	default:
@@ -534,6 +701,11 @@ int __init op_nmi_init(struct oprofile_operations *ops)
	if (ret)
		return ret;

	if (!model->num_virt_counters)
		model->num_virt_counters = model->num_counters;

	mux_init(ops);

	init_sysfs();
	using_nmi = 1;
	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#ifndef OP_COUNTER_H
#define OP_COUNTER_H

#define OP_MAX_COUNTER 8
#define OP_MAX_COUNTER 32

/* Per-perfctr configuration as set via
 * oprofilefs.
+204 −168

File changed.

Preview size limit exceeded, changes collapsed.

+35 −37
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
#define NUM_CCCRS_HT2 9
#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)

#define OP_CTR_OVERFLOW			(1ULL<<31)

static unsigned int num_counters = NUM_COUNTERS_NON_HT;
static unsigned int num_controls = NUM_CONTROLS_NON_HT;

@@ -350,8 +352,6 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = {
#define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
#define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
#define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
#define ESCR_READ(escr, high, ev, i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
#define ESCR_WRITE(escr, high, ev, i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)

#define CCCR_RESERVED_BITS 0x38030FFF
#define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
@@ -361,17 +361,9 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = {
#define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
#define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
#define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))

#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
#define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0)
#define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0)
#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))


/* this assigns a "stagger" to the current CPU, which is used throughout
   the code in this module as an extra array offset, to select the "even"
@@ -515,7 +507,7 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
		if (ev->bindings[i].virt_counter & counter_bit) {

			/* modify ESCR */
			ESCR_READ(escr, high, ev, i);
			rdmsr(ev->bindings[i].escr_address, escr, high);
			ESCR_CLEAR(escr);
			if (stag == 0) {
				ESCR_SET_USR_0(escr, counter_config[ctr].user);
@@ -526,10 +518,11 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
			}
			ESCR_SET_EVENT_SELECT(escr, ev->event_select);
			ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
			ESCR_WRITE(escr, high, ev, i);
			wrmsr(ev->bindings[i].escr_address, escr, high);

			/* modify CCCR */
			CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
			rdmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address,
			      cccr, high);
			CCCR_CLEAR(cccr);
			CCCR_SET_REQUIRED_BITS(cccr);
			CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
@@ -537,7 +530,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
				CCCR_SET_PMI_OVF_0(cccr);
			else
				CCCR_SET_PMI_OVF_1(cccr);
			CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
			wrmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address,
			      cccr, high);
			return;
		}
	}
@@ -548,7 +542,8 @@ static void pmc_setup_one_p4_counter(unsigned int ctr)
}


static void p4_setup_ctrs(struct op_msrs const * const msrs)
static void p4_setup_ctrs(struct op_x86_model_spec const *model,
			  struct op_msrs const * const msrs)
{
	unsigned int i;
	unsigned int low, high;
@@ -564,7 +559,7 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)

	/* clear the cccrs we will use */
	for (i = 0; i < num_counters; i++) {
		if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
		if (unlikely(!msrs->controls[i].addr))
			continue;
		rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
		CCCR_CLEAR(low);
@@ -574,17 +569,18 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)

	/* clear all escrs (including those outside our concern) */
	for (i = num_counters; i < num_controls; i++) {
		if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
		if (unlikely(!msrs->controls[i].addr))
			continue;
		wrmsr(msrs->controls[i].addr, 0, 0);
	}

	/* setup all counters */
	for (i = 0; i < num_counters; ++i) {
		if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) {
		if (counter_config[i].enabled && msrs->controls[i].addr) {
			reset_value[i] = counter_config[i].count;
			pmc_setup_one_p4_counter(i);
			CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
			wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address,
			       -(u64)counter_config[i].count);
		} else {
			reset_value[i] = 0;
		}
@@ -624,14 +620,16 @@ static int p4_check_ctrs(struct pt_regs * const regs,

		real = VIRT_CTR(stag, i);

		CCCR_READ(low, high, real);
		CTR_READ(ctr, high, real);
		if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
		rdmsr(p4_counters[real].cccr_address, low, high);
		rdmsr(p4_counters[real].counter_address, ctr, high);
		if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) {
			oprofile_add_sample(regs, i);
			CTR_WRITE(reset_value[i], real);
			wrmsrl(p4_counters[real].counter_address,
			       -(u64)reset_value[i]);
			CCCR_CLEAR_OVF(low);
			CCCR_WRITE(low, high, real);
			CTR_WRITE(reset_value[i], real);
			wrmsr(p4_counters[real].cccr_address, low, high);
			wrmsrl(p4_counters[real].counter_address,
			       -(u64)reset_value[i]);
		}
	}

@@ -653,9 +651,9 @@ static void p4_start(struct op_msrs const * const msrs)
	for (i = 0; i < num_counters; ++i) {
		if (!reset_value[i])
			continue;
		CCCR_READ(low, high, VIRT_CTR(stag, i));
		rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
		CCCR_SET_ENABLE(low);
		CCCR_WRITE(low, high, VIRT_CTR(stag, i));
		wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
	}
}

@@ -670,9 +668,9 @@ static void p4_stop(struct op_msrs const * const msrs)
	for (i = 0; i < num_counters; ++i) {
		if (!reset_value[i])
			continue;
		CCCR_READ(low, high, VIRT_CTR(stag, i));
		rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
		CCCR_SET_DISABLE(low);
		CCCR_WRITE(low, high, VIRT_CTR(stag, i));
		wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
	}
}

@@ -681,7 +679,7 @@ static void p4_shutdown(struct op_msrs const * const msrs)
	int i;

	for (i = 0; i < num_counters; ++i) {
		if (CTR_IS_RESERVED(msrs, i))
		if (msrs->counters[i].addr)
			release_perfctr_nmi(msrs->counters[i].addr);
	}
	/*
@@ -690,14 +688,14 @@ static void p4_shutdown(struct op_msrs const * const msrs)
	 * This saves a few bits.
	 */
	for (i = num_counters; i < num_controls; ++i) {
		if (CTRL_IS_RESERVED(msrs, i))
		if (msrs->controls[i].addr)
			release_evntsel_nmi(msrs->controls[i].addr);
	}
}


#ifdef CONFIG_SMP
struct op_x86_model_spec const op_p4_ht2_spec = {
struct op_x86_model_spec op_p4_ht2_spec = {
	.num_counters		= NUM_COUNTERS_HT2,
	.num_controls		= NUM_CONTROLS_HT2,
	.fill_in_addresses	= &p4_fill_in_addresses,
@@ -709,7 +707,7 @@ struct op_x86_model_spec const op_p4_ht2_spec = {
};
#endif

struct op_x86_model_spec const op_p4_spec = {
struct op_x86_model_spec op_p4_spec = {
	.num_counters		= NUM_COUNTERS_NON_HT,
	.num_controls		= NUM_CONTROLS_NON_HT,
	.fill_in_addresses	= &p4_fill_in_addresses,
Loading