At Tue, 17 Sep 2002 15:28:44 -0400,
Will Cohen wrote:
> I tried to install the patch to test it out on Athlon. It failed
> installation. What command did you use to generate the patch?
apologies; that was hand-made with a combination of CVS diff and diff,
to present the new files. here is a new one against
oprofile/module/x86, using diff -urN x86 x86-with-models/. I tested
explicitly this time that it applies to oprofile CVS.
diff -urN x86/Makefile.in x86-with-models/Makefile.in
--- x86/Makefile.in Wed Sep 4 10:19:37 2002
+++ x86-with-models/Makefile.in Tue Sep 17 15:37:33 2002
@@ -18,7 +18,8 @@
O_TARGET := arch.o
obj-y := cpu_type.o op_apic.o op_fixmap.o op_rtc.o op_nmi.o \
- op_syscalls.o oprofile_nmi.o
+ op_syscalls.o op_model_ppro.o op_model_athlon.o \
+ oprofile_nmi.o
obj-m := $(O_TARGET)
O_OBJS := $(obj-y)
M_OBJS := $(O_TARGET)
diff -urN x86/op_model_athlon.c x86-with-models/op_model_athlon.c
--- x86/op_model_athlon.c Wed Dec 31 19:00:00 1969
+++ x86-with-models/op_model_athlon.c Tue Sep 17 15:36:08 2002
@@ -0,0 +1,134 @@
+/**
+ * @file op_model_athlon.h
+ * athlon / K7 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ */
+
+#include "op_x86_model.h"
+#include "op_msr.h"
+
+#define ATHLON_NUM_COUNTERS 4
+#define ATHLON_NUM_CONTROLS 4
+
+#define ATHLON_CTR_READ(l,h,bank,c) do {rdmsr(bank->counters[(c)].addr, (l), (h));} while (0);
+#define ATHLON_CTR_WRITE(l,bank,c) do {wrmsr(bank->counters[(c)].addr, -(u32)(l), -1);} while (0);
+#define ATHLON_CTR_SET_ACTIVE(n) (n |= (1<<22))
+#define ATHLON_CTR_SET_INACTIVE(n) (n &= ~(1<<22))
+#define ATHLON_CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define ATHLON_CTRL_READ(l,h,bank,c) do {rdmsr(bank->controls[(c)].addr, (l), (h));} while (0);
+#define ATHLON_CTRL_WRITE(l,h,bank,c) do {wrmsr(bank->controls[(c)].addr, (l), (h));} while (0);
+#define ATHLON_CTRL_CLEAR(x) (x &= (1<<21))
+#define ATHLON_CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define ATHLON_CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
+#define ATHLON_CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
+#define ATHLON_CTRL_SET_UM(val, m) (val |= (m << 8))
+#define ATHLON_CTRL_SET_EVENT(val, e) (val |= e)
+
+static void athlon_fill_in_addresses(struct op_msr_bank *bank)
+{
+ bank->counters[0].addr = MSR_K7_PERFCTR0;
+ bank->counters[1].addr = MSR_K7_PERFCTR1;
+ bank->counters[2].addr = MSR_K7_PERFCTR2;
+ bank->counters[3].addr = MSR_K7_PERFCTR3;
+
+ bank->controls[0].addr = MSR_K7_PERFCTL0;
+ bank->controls[1].addr = MSR_K7_PERFCTL1;
+ bank->controls[2].addr = MSR_K7_PERFCTL2;
+ bank->controls[3].addr = MSR_K7_PERFCTL3;
+}
+
+static void athlon_setup_ctrs(struct op_msr_bank *bank)
+{
+ uint low, high;
+ int i;
+
+ /* clear all counters */
+ for (i = 0 ; i < ATHLON_NUM_CONTROLS; ++i) {
+ ATHLON_CTRL_READ (low, high, bank, i);
+ ATHLON_CTRL_CLEAR (low);
+ ATHLON_CTRL_WRITE (low, high, bank, i);
+ }
+
+ /* avoid a false detection of ctr overflows in NMI handler */
+ for (i = 0; i < ATHLON_NUM_COUNTERS; ++i) {
+ ATHLON_CTR_WRITE(1, bank, i);
+ }
+
+ /* enable active counters */
+ for (i = 0; i < ATHLON_NUM_COUNTERS; ++i) {
+ if (sysctl.ctr[i].event) {
+
+ ATHLON_CTR_WRITE(sysctl.ctr[i].count, bank, i);
+
+ ATHLON_CTRL_READ (low, high, bank, i);
+ ATHLON_CTRL_CLEAR (low);
+ ATHLON_CTRL_SET_ENABLE (low);
+ ATHLON_CTRL_SET_USR (low, sysctl.ctr[i].user);
+ ATHLON_CTRL_SET_KERN (low, sysctl.ctr[i].kernel);
+ ATHLON_CTRL_SET_UM (low, sysctl.ctr[i].unit_mask);
+ ATHLON_CTRL_SET_EVENT (low, sysctl.ctr[i].event);
+ ATHLON_CTRL_WRITE (low, high, bank, i);
+ }
+ }
+}
+
+static void athlon_check_ctrs(uint cpu,
+ struct op_msr_bank *bank,
+ struct pt_regs *regs)
+{
+ ulong low, high;
+ int i;
+ for (i = 0 ; i < ATHLON_NUM_COUNTERS; ++i) {
+ ATHLON_CTR_READ(low, high, bank, i);
+ if (ATHLON_CTR_OVERFLOWED(low)) {
+ op_do_profile(cpu, regs, i);
+ ATHLON_CTR_WRITE(oprof_data[cpu].ctr_count[i],
+ bank, i);
+ }
+ }
+
+}
+
+static void athlon_start(struct op_msr_bank *bank)
+{
+ uint low,high;
+ int i;
+ for (i = 0 ; i < ATHLON_NUM_COUNTERS ; ++i) {
+ if (sysctl.ctr[i].count) {
+ ATHLON_CTR_READ(low, high, bank, i);
+ ATHLON_CTR_SET_ACTIVE(low);
+ ATHLON_CTR_WRITE(low, bank, i);
+ }
+ }
+}
+
+static void athlon_stop(struct op_msr_bank *bank)
+{
+ uint low,high;
+ int i;
+ for (i = 0 ; i < ATHLON_NUM_COUNTERS ; ++i) {
+ if (sysctl.ctr[i].count) {
+ ATHLON_CTR_READ(low, high, bank, i);
+ ATHLON_CTR_SET_INACTIVE(low);
+ ATHLON_CTR_WRITE(low, bank, i);
+ }
+ }
+}
+
+
+struct op_x86_model_spec op_athlon_spec = {
+ .num_counters = ATHLON_NUM_COUNTERS,
+ .num_controls = ATHLON_NUM_CONTROLS,
+ .fill_in_addresses = & athlon_fill_in_addresses,
+ .setup_ctrs = & athlon_setup_ctrs,
+ .check_ctrs = & athlon_check_ctrs,
+ .start = & athlon_start,
+ .stop = & athlon_stop
+};
diff -urN x86/op_model_ppro.c x86-with-models/op_model_ppro.c
--- x86/op_model_ppro.c Wed Dec 31 19:00:00 1969
+++ x86-with-models/op_model_ppro.c Tue Sep 17 15:36:08 2002
@@ -0,0 +1,119 @@
+/**
+ * @file op_model_ppro.h
+ * pentium pro / P6 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ */
+
+#include "op_x86_model.h"
+
+#define PPRO_NUM_COUNTERS 2
+#define PPRO_NUM_CONTROLS 2
+
+#define PPRO_CTR_READ(l,h,bank,c) do {rdmsr(bank->counters[(c)].addr, (l), (h));} while (0);
+#define PPRO_CTR_WRITE(l,bank,c) do {wrmsr(bank->counters[(c)].addr, -(u32)(l), -1);} while (0);
+#define PPRO_CTR_SET_ACTIVE(n) (n |= (1<<22))
+#define PPRO_CTR_SET_INACTIVE(n) (n &= ~(1<<22))
+#define PPRO_CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define PPRO_CTRL_READ(l,h,bank,c) do {rdmsr((bank->controls[(c)].addr), (l), (h));} while (0);
+#define PPRO_CTRL_WRITE(l,h,bank,c) do {wrmsr((bank->controls[(c)].addr), (l), (h));} while (0);
+#define PPRO_CTRL_CLEAR(x) (x &= (1<<21))
+#define PPRO_CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define PPRO_CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
+#define PPRO_CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
+#define PPRO_CTRL_SET_UM(val, m) (val |= (m << 8))
+#define PPRO_CTRL_SET_EVENT(val, e) (val |= e)
+
+static void ppro_fill_in_addresses(struct op_msr_bank *bank)
+{
+ bank->counters[0].addr = MSR_P6_PERFCTR0;
+ bank->counters[1].addr = MSR_P6_PERFCTR1;
+
+ bank->controls[0].addr = MSR_P6_EVNTSEL0;
+ bank->controls[1].addr = MSR_P6_EVNTSEL1;
+}
+
+static void ppro_setup_ctrs(struct op_msr_bank *bank)
+{
+ uint low, high;
+ int i;
+
+ /* clear all counters */
+ for (i = 0 ; i < PPRO_NUM_CONTROLS; ++i) {
+ PPRO_CTRL_READ (low, high, bank, i);
+ PPRO_CTRL_CLEAR (low);
+ PPRO_CTRL_WRITE (low, high, bank, i);
+ }
+
+ /* avoid a false detection of ctr overflows in NMI handler */
+ for (i = 0; i < PPRO_NUM_COUNTERS; ++i) {
+ PPRO_CTR_WRITE(1, bank, i);
+ }
+
+ /* enable active counters */
+ for (i = 0; i < PPRO_NUM_COUNTERS; ++i) {
+ if (sysctl.ctr[i].event) {
+
+ PPRO_CTR_WRITE(sysctl.ctr[i].count, bank, i);
+
+ PPRO_CTRL_READ (low, high, bank, i);
+ PPRO_CTRL_CLEAR (low);
+ PPRO_CTRL_SET_ENABLE (low);
+ PPRO_CTRL_SET_USR (low, sysctl.ctr[i].user);
+ PPRO_CTRL_SET_KERN (low, sysctl.ctr[i].kernel);
+ PPRO_CTRL_SET_UM (low, sysctl.ctr[i].unit_mask);
+ PPRO_CTRL_SET_EVENT (low, sysctl.ctr[i].event);
+ PPRO_CTRL_WRITE (low, high, bank, i);
+ }
+ }
+}
+
+static void ppro_check_ctrs(uint cpu,
+ struct op_msr_bank *bank,
+ struct pt_regs *regs)
+{
+ ulong low, high;
+ int i;
+ for (i = 0 ; i < PPRO_NUM_COUNTERS; ++i) {
+ PPRO_CTR_READ(low, high, bank, i);
+ if (PPRO_CTR_OVERFLOWED(low)) {
+ op_do_profile(cpu, regs, i);
+ PPRO_CTR_WRITE(oprof_data[cpu].ctr_count[i],
+ bank, i);
+ }
+ }
+
+}
+
+static void ppro_start(struct op_msr_bank *bank)
+{
+ uint low,high;
+ PPRO_CTR_READ(low, high, bank, 0);
+ PPRO_CTR_SET_ACTIVE(low);
+ PPRO_CTR_WRITE(low, bank, 0);
+}
+
+static void ppro_stop(struct op_msr_bank *bank)
+{
+ uint low,high;
+ PPRO_CTR_READ(low, high, bank, 0);
+ PPRO_CTR_SET_INACTIVE(low);
+ PPRO_CTR_WRITE(low, bank, 0);
+}
+
+
+struct op_x86_model_spec op_ppro_spec = {
+ .num_counters = PPRO_NUM_COUNTERS,
+ .num_controls = PPRO_NUM_CONTROLS,
+ .fill_in_addresses = & ppro_fill_in_addresses,
+ .setup_ctrs = & ppro_setup_ctrs,
+ .check_ctrs = & ppro_check_ctrs,
+ .start = & ppro_start,
+ .stop = & ppro_stop
+};
diff -urN x86/op_nmi.c x86-with-models/op_nmi.c
--- x86/op_nmi.c Sat Sep 7 14:19:39 2002
+++ x86-with-models/op_nmi.c Tue Sep 17 15:40:35 2002
@@ -14,173 +14,95 @@
#include "op_apic.h"
#include "op_events.h"
#include "op_util.h"
+#include "op_x86_model.h"
-/* the MSRs we need */
-static uint perfctr_msr[OP_MAX_COUNTERS];
-static uint eventsel_msr[OP_MAX_COUNTERS];
+static struct op_msr_bank msr_banks [OP_MAX_CPUS];
-/* number of counters physically present */
-static uint op_nr_counters = 2;
-
-/* whether we enable for each counter (athlon) or globally (intel) */
-static int separate_running_bit;
+static struct op_x86_model_spec *model(void)
+{
+ static struct op_x86_model_spec *mod = NULL;
+ if (! mod) {
+
+ /* pick out our per-model function table */
+ switch (sysctl.cpu_type) {
+ case CPU_ATHLON:
+ mod = & op_athlon_spec;
+ break;
+
+ case CPU_P4:
+ mod = & op_p4_spec;
+ break;
+
+ default:
+ mod = & op_ppro_spec;
+ break;
+ }
+ }
+ return mod;
+}
/* ---------------- NMI handler ------------------ */
/* preempt: all things inside the interrupt handler are preempt safe : we
* never reenable interrupt */
-static void op_check_ctr(uint cpu, struct pt_regs *regs, int ctr)
-{
- ulong l,h;
- get_perfctr(l, h, ctr);
- if (ctr_overflowed(l)) {
- op_do_profile(cpu, regs, ctr);
- set_perfctr(oprof_data[cpu].ctr_count[ctr], ctr);
- }
-}
-
asmlinkage void op_do_nmi(struct pt_regs * regs)
{
- uint cpu = op_cpu_id();
- int i;
+ uint cpu;
+ struct op_msr_bank *bank;
- for (i = 0 ; i < op_nr_counters ; ++i)
- op_check_ctr(cpu, regs, i);
+ cpu = op_cpu_id ();
+ bank = & (msr_banks [cpu]);
+ model()->check_ctrs (cpu, bank, regs);
}
/* ---------------- PMC setup ------------------ */
-static void pmc_fill_in(uint *val, u8 kernel, u8 user, u8 event, u8 um)
+static int pmc_setup_ctr(void *dummy)
{
- /* enable interrupt generation */
- *val |= (1<<20);
- /* enable/disable chosen OS and USR counting */
- (user) ? (*val |= (1<<16))
- : (*val &= ~(1<<16));
-
- (kernel) ? (*val |= (1<<17))
- : (*val &= ~(1<<17));
-
- /* what are we counting ? */
- *val |= event;
- *val |= (um<<8);
-}
-
-static void pmc_setup(void *dummy)
-{
- uint low, high;
- int i;
-
- /* IA Vol. 3 Figure 15-3 */
-
- /* Stop and clear all counter: IA32 use bit 22 of eventsel_msr0 to
- * enable/disable all counter, AMD use separate bit 22 in each msr,
- * all bits are cleared except the reserved bits 21 */
- for (i = 0 ; i < op_nr_counters ; ++i) {
- rdmsr(eventsel_msr[i], low, high);
- wrmsr(eventsel_msr[i], low & (1 << 21), high);
+ uint cpu;
+ struct op_msr_bank *bank;
- /* avoid a false detection of ctr overflow in NMI handler */
- wrmsr(perfctr_msr[i], -1, -1);
- }
-
- /* setup each counter */
- for (i = 0 ; i < op_nr_counters ; ++i) {
- if (sysctl.ctr[i].event) {
- rdmsr(eventsel_msr[i], low, high);
-
- low &= 1 << 21; /* do not touch the reserved bit */
- set_perfctr(sysctl.ctr[i].count, i);
-
- pmc_fill_in(&low, sysctl.ctr[i].kernel, sysctl.ctr[i].user,
- sysctl.ctr[i].event, sysctl.ctr[i].unit_mask);
-
- wrmsr(eventsel_msr[i], low, high);
- }
- }
-
- /* Here all setup is made except the start/stop bit 22, counter
- * disabled contains zeros in the eventsel msr except the reserved bit
- * 21 */
+ cpu = op_cpu_id ();
+ bank = & (msr_banks [cpu]);
+ model()->setup_ctrs (bank);
+ return 0;
}
static int pmc_setup_all(void)
{
- if ((smp_call_function(pmc_setup, NULL, 0, 1)))
+ if (smp_call_function(pmc_setup_ctr, NULL, 0, 1))
return -EFAULT;
-
- pmc_setup(NULL);
+ pmc_setup_ctr (NULL);
return 0;
}
-inline static void pmc_start_P6(void)
-{
- uint low,high;
-
- rdmsr(eventsel_msr[0], low, high);
- wrmsr(eventsel_msr[0], low | (1 << 22), high);
-}
-
-inline static void pmc_start_Athlon(void)
+static void pmc_start(void *info)
{
- uint low,high;
- int i;
+ uint cpu;
+ struct op_msr_bank *bank;
- for (i = 0 ; i < op_nr_counters ; ++i) {
- if (sysctl.ctr[i].count) {
- rdmsr(eventsel_msr[i], low, high);
- wrmsr(eventsel_msr[i], low | (1 << 22), high);
- }
- }
-}
+ cpu = op_cpu_id ();
+ bank = & (msr_banks [cpu]);
-static void pmc_start(void *info)
-{
- if (info && (*((uint *)info) != op_cpu_id()))
+ if (info && (*((uint *)info) != cpu))
return;
- /* assert: all enable counter are setup except the bit start/stop,
- * all counter disable contains zeroes (except perhaps the reserved
- * bit 21), counter disable contains -1 sign extended in msr count */
-
- /* enable all needed counter */
- if (separate_running_bit == 0)
- pmc_start_P6();
- else
- pmc_start_Athlon();
+ model()->start (bank);
}
-inline static void pmc_stop_P6(void)
-{
- uint low,high;
- rdmsr(eventsel_msr[0], low, high);
- wrmsr(eventsel_msr[0], low & ~(1 << 22), high);
-}
-
-inline static void pmc_stop_Athlon(void)
+static void pmc_stop(void *info)
{
- uint low,high;
- int i;
+ uint cpu;
+ struct op_msr_bank *bank;
- for (i = 0 ; i < op_nr_counters ; ++i) {
- if (sysctl.ctr[i].count) {
- rdmsr(eventsel_msr[i], low, high);
- wrmsr(eventsel_msr[i], low & ~(1 << 22), high);
- }
- }
-}
+ cpu = op_cpu_id ();
+ bank = & (msr_banks [cpu]);
-static void pmc_stop(void *info)
-{
- if (info && (*((uint *)info) != op_cpu_id()))
+ if (info && (*((uint *)info) != cpu))
return;
- /* disable counters */
- if (separate_running_bit == 0)
- pmc_stop_P6();
- else
- pmc_stop_Athlon();
+ model()->stop (bank);
}
static void pmc_select_start(uint cpu)
@@ -206,7 +128,7 @@
for (cpu = 0 ; cpu < OP_MAX_CPUS; cpu++) {
struct _oprof_data * data = &oprof_data[cpu];
- for (i = 0 ; i < op_nr_counters ; ++i) {
+ for (i = 0 ; i < model()->num_counters ; ++i) {
if (sysctl.ctr[i].enabled)
data->ctr_count[i] = sysctl.ctr[i].count;
else
@@ -231,11 +153,11 @@
int i;
int enabled = 0;
int ok = 0;
-
- for (i = 0; i < op_nr_counters ; i++) {
+
+ for (i = 0; i < model()->num_counters; i++) {
int min_count;
int ret;
-
+
if (!sysctl.ctr[i].enabled)
continue;
@@ -267,8 +189,8 @@
printk(KERN_ERR "oprofile: ctr%d: %d: can't count event for this counter\n", i,
sysctl.ctr[i].event);
}
-
- if (ret != OP_OK_EVENT)
+
+ if (ret != OP_OK_EVENT)
ok = -EINVAL;
}
@@ -280,50 +202,81 @@
return ok;
}
-static uint saved_perfctr_low[OP_MAX_COUNTERS];
-static uint saved_perfctr_high[OP_MAX_COUNTERS];
-static uint saved_eventsel_low[OP_MAX_COUNTERS];
-static uint saved_eventsel_high[OP_MAX_COUNTERS];
-static int pmc_init(void)
+static int pmc_save_registers(void *dummy)
{
- int i;
- int err = 0;
+ uint i;
+ uint cpu;
+ struct op_msr_bank *bank;
+
+ cpu = op_cpu_id();
+ bank = & (msr_banks [cpu]);
+
+ bank->counters = kmalloc (model()->num_counters *
+ sizeof (struct op_msr), GFP_KERNEL);
+ if (! bank->counters)
+ return -EFAULT;
+
+ bank->controls = kmalloc (model()->num_controls *
+ sizeof (struct op_msr), GFP_KERNEL);
+ if (! bank->controls)
+ return -EFAULT;
- if (sysctl.cpu_type == CPU_ATHLON) {
- op_nr_counters = 4;
- separate_running_bit = 1;
+ model()->fill_in_addresses (bank);
+
+ for (i = 0; i < model()->num_counters; ++i) {
+ rdmsr (bank->counters[i].addr,
+ bank->counters[i].saved_low,
+ bank->counters[i].saved_high);
}
- /* let's use the right MSRs */
- switch (sysctl.cpu_type) {
- case CPU_ATHLON:
- eventsel_msr[0] = MSR_K7_PERFCTL0;
- eventsel_msr[1] = MSR_K7_PERFCTL1;
- eventsel_msr[2] = MSR_K7_PERFCTL2;
- eventsel_msr[3] = MSR_K7_PERFCTL3;
- perfctr_msr[0] = MSR_K7_PERFCTR0;
- perfctr_msr[1] = MSR_K7_PERFCTR1;
- perfctr_msr[2] = MSR_K7_PERFCTR2;
- perfctr_msr[3] = MSR_K7_PERFCTR3;
- break;
- default:
- eventsel_msr[0] = MSR_P6_EVNTSEL0;
- eventsel_msr[1] = MSR_P6_EVNTSEL1;
- perfctr_msr[0] = MSR_P6_PERFCTR0;
- perfctr_msr[1] = MSR_P6_PERFCTR1;
- break;
+ for (i = 0; i < model()->num_controls; ++i) {
+ rdmsr (bank->controls[i].addr,
+ bank->controls[i].saved_low,
+ bank->controls[i].saved_high);
}
+ return 0;
+}
+
+static int pmc_restore_registers(void *dummy)
+{
+ uint i;
+ uint cpu;
+ struct op_msr_bank *bank;
+
+ cpu = op_cpu_id();
+ bank = & (msr_banks [cpu]);
- for (i = 0 ; i < op_nr_counters ; ++i) {
- rdmsr(eventsel_msr[i], saved_eventsel_low[i], saved_eventsel_high[i]);
- rdmsr(perfctr_msr[i], saved_perfctr_low[i], saved_perfctr_high[i]);
+ for (i = 0; i < model()->num_controls; ++i) {
+ wrmsr (bank->controls[i].addr,
+ bank->controls[i].saved_low,
+ bank->controls[i].saved_high);
}
- /* setup each counter */
- if ((err = apic_setup()))
+ for (i = 0; i < model()->num_counters; ++i) {
+ wrmsr (bank->counters[i].addr,
+ bank->counters[i].saved_low,
+ bank->counters[i].saved_high);
+ }
+
+ kfree (bank->controls);
+ kfree (bank->counters);
+ return 0;
+}
+
+static int pmc_init(void)
+{
+ int err = 0;
+ if ((err = smp_call_function(pmc_save_registers, NULL, 0, 1))) {
+ smp_call_function(pmc_restore_registers, NULL, 0, 1);
goto out;
+ }
+ pmc_save_registers(NULL);
+
+ if ((err = apic_setup()))
+ goto out;
+
if ((err = smp_call_function(lvtpc_apic_setup, NULL, 0, 1))) {
lvtpc_apic_restore(NULL);
}
@@ -334,17 +287,13 @@
static void pmc_deinit(void)
{
- int i;
-
smp_call_function(lvtpc_apic_restore, NULL, 0, 1);
lvtpc_apic_restore(NULL);
- for (i = 0 ; i < op_nr_counters ; ++i) {
- wrmsr(eventsel_msr[i], saved_eventsel_low[i], saved_eventsel_high[i]);
- wrmsr(perfctr_msr[i], saved_perfctr_low[i], saved_perfctr_high[i]);
- }
-
apic_restore();
+
+ smp_call_function(pmc_restore_registers, NULL, 0, 1);
+ pmc_restore_registers(NULL);
}
static char *names[] = { "0", "1", "2", "3", "4", };
@@ -355,7 +304,8 @@
ctl_table * tab;
int i, j;
- for (i=0; i < op_nr_counters; i++) {
+ /* now init the sysctls */
+ for (i=0; i < model()->num_counters; i++) {
next->ctl_name = 1;
next->procname = names[i];
next->mode = 0755;
@@ -389,8 +339,7 @@
static void pmc_remove_sysctls(ctl_table * next)
{
int i;
-
- for (i=0; i < op_nr_counters; i++) {
+ for (i=0; i < model()->num_counters; i++) {
kfree(next->child);
next++;
}
diff -urN x86/op_x86_model.h x86-with-models/op_x86_model.h
--- x86/op_x86_model.h Wed Dec 31 19:00:00 1969
+++ x86-with-models/op_x86_model.h Tue Sep 17 15:36:08 2002
@@ -0,0 +1,46 @@
+#ifndef OP_X86_MODEL_H
+#define OP_X86_MODEL_H
+
+#include "oprofile.h"
+
+/**
+ * @file op_x86_model.h
+ * interface to x86 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+struct pt_regs;
+struct op_x86_model_spec;
+
+struct op_msr {
+ uint addr;
+ uint saved_low;
+ uint saved_high;
+};
+
+struct op_msr_bank {
+ struct op_msr *counters;
+ struct op_msr *controls;
+};
+
+struct op_x86_model_spec {
+ const uint num_counters;
+ const uint num_controls;
+ void (* fill_in_addresses)(struct op_msr_bank *);
+ void (* setup_ctrs)(struct op_msr_bank *bank);
+ void (* check_ctrs)(uint cpu,
+ struct op_msr_bank *bank,
+ struct pt_regs *regs);
+ void (* start)(struct op_msr_bank *bank);
+ void (* stop)(struct op_msr_bank *bank);
+};
+
+extern struct op_x86_model_spec op_ppro_spec;
+extern struct op_x86_model_spec op_athlon_spec;
+extern struct op_x86_model_spec op_p4_spec;
+
+#endif /* OP_X86_MODEL_H */
|