
From: Philippe Elie <phil.el@wanadoo.fr>

- oprofile is currently only profiling one sibling.  Fix that with
  appropriate register settings.

- fix an oops which could occur if the userspace driver were to request a
  non-existent resource.

- in NMI handler counter_config[i].event is accessible from user space so
  user can change the event during profiling by echo xxx >
  /dev/oprofile/event

- event mask was wrong, the bit field is 6 bits length not 5, events
  SSE_INPUT_ASSIST and X87_SIMD_MOVES_UOP was affected by masking high bit of
  event number.



 arch/i386/oprofile/op_model_p4.c |  107 ++++++++++++++++++++++++---------------
 1 files changed, 67 insertions(+), 40 deletions(-)

diff -puN arch/i386/oprofile/op_model_p4.c~p4-oprofile-fix arch/i386/oprofile/op_model_p4.c
--- 25/arch/i386/oprofile/op_model_p4.c~p4-oprofile-fix	2003-04-13 12:22:38.000000000 -0700
+++ 25-akpm/arch/i386/oprofile/op_model_p4.c	2003-04-13 12:22:54.000000000 -0700
@@ -31,7 +31,6 @@
 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
 
 static unsigned int num_counters = NUM_COUNTERS_NON_HT;
-static unsigned int num_cccrs = NUM_CCCRS_NON_HT;
 
 
 /* this has to be checked dynamically since the
@@ -40,10 +39,17 @@ static unsigned int num_cccrs = NUM_CCCR
 static inline void setup_num_counters(void)
 {
 #ifdef CONFIG_SMP
-	if (smp_num_siblings == 2) {		
+	if (smp_num_siblings == 2)
 		num_counters = NUM_COUNTERS_HT2;
-		num_cccrs = NUM_CCCRS_HT2;
-	}
+#endif
+}
+
+static int inline addr_increment(void)
+{
+#ifdef CONFIG_SMP
+	return smp_num_siblings == 2 ? 2 : 1;
+#else
+	return 1;
 #endif
 }
 
@@ -65,7 +71,7 @@ struct p4_event_binding {
 };
 
 /* nb: these CTR_* defines are a duplicate of defines in
-   libop/op_events.c. */
+   event/i386.p4*events. */
 
 
 #define CTR_BPU_0      (1 << 0)
@@ -88,6 +94,17 @@ static struct p4_counter_binding p4_coun
 	{ 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] = {
@@ -167,13 +184,13 @@ static struct p4_event_binding p4_events
 	{ /* IOQ_ALLOCATION */
 		0x06, 0x03, 
 		{ { CTR_BPU_0, MSR_P4_FSB_ESCR0},
-		  {-1,-1} }
+		  { 0, 0 } }
 	},
 
 	{ /* IOQ_ACTIVE_ENTRIES */
 		0x06, 0x1a, 
 		{ { CTR_BPU_2, MSR_P4_FSB_ESCR1},
-		  {-1,-1} }
+		  { 0, 0 } }
 	},
 
 	{ /* FSB_DATA_ACTIVITY */
@@ -185,13 +202,13 @@ static struct p4_event_binding p4_events
 	{ /* BSQ_ALLOCATION */
 		0x07, 0x05, 
 		{ { CTR_BPU_0, MSR_P4_BSU_ESCR0},
-		  {-1,-1} }
+		  { 0, 0 } }
 	},
 
 	{ /* BSQ_ACTIVE_ENTRIES */
 		0x07, 0x06,
 		{ { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},  
-		  {-1,-1} }
+		  { 0, 0 } }
 	},
 
 	{ /* X87_ASSIST */
@@ -336,7 +353,7 @@ static struct p4_event_binding p4_events
 #define ESCR_SET_OS_0(escr, os) ((escr) |= (((os) & 1) << 3))
 #define ESCR_SET_USR_1(escr, usr) ((escr) |= (((usr) & 1)))
 #define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
-#define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x1f) << 25))
+#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);
@@ -358,15 +375,11 @@ static struct p4_event_binding p4_events
 #define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0);
 #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
 
-/* these access the underlying cccrs 1-18, not the subset of 8 bound to "virtual counters" */
-#define RAW_CCCR_READ(low, high, i) do {rdmsr (MSR_P4_BPU_CCCR0 + (i), (low), (high));} while (0);
-#define RAW_CCCR_WRITE(low, high, i) do {wrmsr (MSR_P4_BPU_CCCR0 + (i), (low), (high));} while (0);
-
 
 /* 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"
    or "odd" part of all the divided resources. */
-static inline unsigned int get_stagger(void)
+static unsigned int get_stagger(void)
 {
 #ifdef CONFIG_SMP
 	int cpu;
@@ -395,29 +408,33 @@ static void p4_fill_in_addresses(struct 
 	setup_num_counters();
 	stag = get_stagger();
 
-	/* the 8 counter registers we pay attention to */
-	for (i = 0; i < num_counters; ++i)
+	/* the counter registers we pay attention to */
+	for (i = 0; i < num_counters; ++i) {
 		msrs->counters.addrs[i] = 
 			p4_counters[VIRT_CTR(stag, i)].counter_address;
+	}
+
+	/* FIXME: bad feeling, we don't save the 10 counters we don't use. */
 
 	/* 18 CCCR registers */
-	for (i=stag, addr = MSR_P4_BPU_CCCR0;
-	     addr <= MSR_P4_IQ_CCCR5; ++i, addr += (1 + stag)) 
+	for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
+	     addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
 		msrs->controls.addrs[i] = addr;
+	}
 	
-	/* 43 ESCR registers */
-	for (addr = MSR_P4_BSU_ESCR0;
-	     addr <= MSR_P4_SSU_ESCR0; ++i, addr += (1 + stag)){ 
+	/* 43 ESCR registers in three discontiguous group */
+	for (addr = MSR_P4_BSU_ESCR0 + stag;
+	     addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { 
 		msrs->controls.addrs[i] = addr;
 	}
 	
-	for (addr = MSR_P4_MS_ESCR0;
-	     addr <= MSR_P4_TC_ESCR1; ++i, addr += (1 + stag)){ 
+	for (addr = MSR_P4_MS_ESCR0 + stag;
+	     addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) { 
 		msrs->controls.addrs[i] = addr;
 	}
 	
-	for (addr = MSR_P4_IX_ESCR0;
-	     addr <= MSR_P4_CRU_ESCR3; ++i, addr += (1 + stag)){ 
+	for (addr = MSR_P4_IX_ESCR0 + stag;
+	     addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) { 
 		msrs->controls.addrs[i] = addr;
 	}
 
@@ -435,7 +452,7 @@ static void p4_fill_in_addresses(struct 
 
 	} else {
 		/* and two copies of the second to the odd thread,
-		   for the 31st and 32nd control registers */
+		   for the 22st and 23nd control registers */
 		msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR5;
 		msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR5;
 	}
@@ -456,7 +473,7 @@ static void pmc_setup_one_p4_counter(uns
 	stag = get_stagger();
 	
 	/* convert from counter *number* to counter *bit* */
-	counter_bit = 1 << ctr;
+	counter_bit = 1 << VIRT_CTR(stag, ctr);
 	
 	/* find our event binding structure. */
 	if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
@@ -470,7 +487,7 @@ static void pmc_setup_one_p4_counter(uns
 	
 	for (i = 0; i < maxbind; i++) {
 		if (ev->bindings[i].virt_counter & counter_bit) {
-			
+
 			/* modify ESCR */
 			ESCR_READ(escr, high, ev, i);
 			ESCR_CLEAR(escr);
@@ -499,6 +516,10 @@ static void pmc_setup_one_p4_counter(uns
 			return;
 		}
 	}
+
+	printk(KERN_ERR 
+	       "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
+	       counter_config[ctr].event, stag, ctr);
 }
 
 
@@ -517,27 +538,35 @@ static void p4_setup_ctrs(struct op_msrs
 		return;
 	}
 
-	/* clear all cccrs (including those outside our concern) */
-	for (i = stag ; i < num_cccrs ; i += (1 + stag)) {
-		RAW_CCCR_READ(low, high, i);
+	/* clear the cccrs we will use */
+	for (i = 0 ; i < num_counters ; i++) {
+		rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
+		CCCR_CLEAR(low);
+		CCCR_SET_REQUIRED_BITS(low);
+		wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
+	}
+
+	/* clear cccrs outside our concern */
+	for (i = stag ; i < NUM_UNUSED_CCCRS ; i += addr_increment()) {
+		rdmsr(p4_unused_cccr[i], low, high);
 		CCCR_CLEAR(low);
 		CCCR_SET_REQUIRED_BITS(low);
-		RAW_CCCR_WRITE(low, high, i);
+		wrmsr(p4_unused_cccr[i], low, high);
 	}
 
-	/* clear all escrs (including those outside out concern) */
+	/* clear all escrs (including those outside our concern) */
 	for (addr = MSR_P4_BSU_ESCR0 + stag;
-	     addr <= MSR_P4_SSU_ESCR0; addr += (1 + stag)){ 
+	     addr <= MSR_P4_SSU_ESCR0; addr += addr_increment()) { 
 		wrmsr(addr, 0, 0);
 	}
 	
 	for (addr = MSR_P4_MS_ESCR0 + stag;
-	     addr <= MSR_P4_TC_ESCR1; addr += (1 + stag)){ 
+	     addr <= MSR_P4_TC_ESCR1; addr += addr_increment()){ 
 		wrmsr(addr, 0, 0);
 	}
 	
 	for (addr = MSR_P4_IX_ESCR0 + stag;
-	     addr <= MSR_P4_CRU_ESCR3; addr += (1 + stag)){ 
+	     addr <= MSR_P4_CRU_ESCR3; addr += addr_increment()){ 
 		wrmsr(addr, 0, 0);
 	}
 
@@ -576,7 +605,7 @@ static int p4_check_ctrs(unsigned int co
 
 	for (i = 0; i < num_counters; ++i) {
 		
-		if (!counter_config[i].event) 
+		if (!reset_value[i]) 
 			continue;
 
 		/* 
@@ -606,8 +635,6 @@ static int p4_check_ctrs(unsigned int co
 			CCCR_CLEAR_OVF(low);
 			CCCR_WRITE(low, high, real);
  			CTR_WRITE(reset_value[i], real);
-			/* P4 quirk: you have to re-unmask the apic vector */
-			apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
 		}
 	}
 

_
