Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / arch / i386 / oprofile / op_model_p4.c
index 7c61d35..4792592 100644 (file)
@@ -32,7 +32,7 @@
 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
 
 static unsigned int num_counters = NUM_COUNTERS_NON_HT;
-
+static unsigned int num_controls = NUM_CONTROLS_NON_HT;
 
 /* this has to be checked dynamically since the
    hyper-threadedness of a chip is discovered at
@@ -40,8 +40,10 @@ static unsigned int num_counters = NUM_COUNTERS_NON_HT;
 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_controls = NUM_CONTROLS_HT2;
+       }
 #endif
 }
 
@@ -97,15 +99,6 @@ static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
 
 #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] = {
@@ -372,6 +365,8 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = {
 #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))
@@ -401,29 +396,34 @@ static unsigned long reset_value[NUM_COUNTERS_NON_HT];
 static void p4_fill_in_addresses(struct op_msrs * const msrs)
 {
        unsigned int i; 
-       unsigned int addr, stag;
+       unsigned int addr, cccraddr, stag;
 
        setup_num_counters();
        stag = get_stagger();
 
-       /* the counter registers we pay attention to */
+       /* initialize some registers */
        for (i = 0; i < num_counters; ++i) {
-               msrs->counters[i].addr = 
-                       p4_counters[VIRT_CTR(stag, i)].counter_address;
+               msrs->counters[i].addr = 0;
        }
-
-       /* FIXME: bad feeling, we don't save the 10 counters we don't use. */
-
-       /* 18 CCCR registers */
-       for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
-            addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
-               msrs->controls[i].addr = addr;
+       for (i = 0; i < num_controls; ++i) {
+               msrs->controls[i].addr = 0;
        }
        
+       /* the counter & cccr registers we pay attention to */
+       for (i = 0; i < num_counters; ++i) {
+               addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
+               cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
+               if (reserve_perfctr_nmi(addr)){
+                       msrs->counters[i].addr = addr;
+                       msrs->controls[i].addr = cccraddr;
+               }
+       }
+
        /* 43 ESCR registers in three or four discontiguous group */
        for (addr = MSR_P4_BSU_ESCR0 + stag;
             addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
-               msrs->controls[i].addr = addr;
+               if (reserve_evntsel_nmi(addr))
+                       msrs->controls[i].addr = addr;
        }
 
        /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
@@ -431,47 +431,57 @@ static void p4_fill_in_addresses(struct op_msrs * const msrs)
        if (boot_cpu_data.x86_model >= 0x3) {
                for (addr = MSR_P4_BSU_ESCR0 + stag;
                     addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
-                       msrs->controls[i].addr = addr;
+                       if (reserve_evntsel_nmi(addr))
+                               msrs->controls[i].addr = addr;
                }
        } else {
                for (addr = MSR_P4_IQ_ESCR0 + stag;
                     addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
-                       msrs->controls[i].addr = addr;
+                       if (reserve_evntsel_nmi(addr))
+                               msrs->controls[i].addr = addr;
                }
        }
 
        for (addr = MSR_P4_RAT_ESCR0 + stag;
             addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
-               msrs->controls[i].addr = addr;
+               if (reserve_evntsel_nmi(addr))
+                       msrs->controls[i].addr = addr;
        }
        
        for (addr = MSR_P4_MS_ESCR0 + stag;
             addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) { 
-               msrs->controls[i].addr = addr;
+               if (reserve_evntsel_nmi(addr))
+                       msrs->controls[i].addr = addr;
        }
        
        for (addr = MSR_P4_IX_ESCR0 + stag;
             addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) { 
-               msrs->controls[i].addr = addr;
+               if (reserve_evntsel_nmi(addr))
+                       msrs->controls[i].addr = addr;
        }
 
        /* there are 2 remaining non-contiguously located ESCRs */
 
        if (num_counters == NUM_COUNTERS_NON_HT) {              
                /* standard non-HT CPUs handle both remaining ESCRs*/
-               msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
-               msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
+               if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
+                       msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
+               if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
+                       msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
 
        } else if (stag == 0) {
                /* HT CPUs give the first remainder to the even thread, as
                   the 32nd control register */
-               msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
+               if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
+                       msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
 
        } else {
                /* and two copies of the second to the odd thread,
                   for the 22st and 23nd control registers */
-               msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
-               msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
+               if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
+                       msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
+                       msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
+               }
        }
 }
 
@@ -544,7 +554,6 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
 {
        unsigned int i;
        unsigned int low, high;
-       unsigned int addr;
        unsigned int stag;
 
        stag = get_stagger();
@@ -557,59 +566,24 @@ 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)))
+                       continue;
                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);
-               wrmsr(p4_unused_cccr[i], low, high);
-       }
-
        /* clear all escrs (including those outside our concern) */
-       for (addr = MSR_P4_BSU_ESCR0 + stag;
-            addr <  MSR_P4_IQ_ESCR0; addr += addr_increment()) {
-               wrmsr(addr, 0, 0);
-       }
-
-       /* On older models clear also MSR_P4_IQ_ESCR0/1 */
-       if (boot_cpu_data.x86_model < 0x3) {
-               wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
-               wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
-       }
-
-       for (addr = MSR_P4_RAT_ESCR0 + stag;
-            addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
-               wrmsr(addr, 0, 0);
-       }
-       
-       for (addr = MSR_P4_MS_ESCR0 + 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 += addr_increment()){ 
-               wrmsr(addr, 0, 0);
+       for (i = num_counters; i < num_controls; i++) {
+               if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
+                       continue;
+               wrmsr(msrs->controls[i].addr, 0, 0);
        }
 
-       if (num_counters == NUM_COUNTERS_NON_HT) {              
-               wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
-               wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
-       } else if (stag == 0) {
-               wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
-       } else {
-               wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
-       }               
-       
        /* setup all counters */
        for (i = 0 ; i < num_counters ; ++i) {
-               if (counter_config[i].enabled) {
+               if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs,i))) {
                        reset_value[i] = counter_config[i].count;
                        pmc_setup_one_p4_counter(i);
                        CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
@@ -696,12 +670,32 @@ static void p4_stop(struct op_msrs const * const msrs)
        stag = get_stagger();
 
        for (i = 0; i < num_counters; ++i) {
+               if (!reset_value[i])
+                       continue;
                CCCR_READ(low, high, VIRT_CTR(stag, i));
                CCCR_SET_DISABLE(low);
                CCCR_WRITE(low, high, VIRT_CTR(stag, i));
        }
 }
 
+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))
+                       release_perfctr_nmi(msrs->counters[i].addr);
+       }
+       /* some of the control registers are specially reserved in
+        * conjunction with the counter registers (hence the starting offset).
+        * This saves a few bits.
+        */
+       for (i = num_counters ; i < num_controls ; ++i) {
+               if (CTRL_IS_RESERVED(msrs,i))
+                       release_evntsel_nmi(msrs->controls[i].addr);
+       }
+}
+
 
 #ifdef CONFIG_SMP
 struct op_x86_model_spec const op_p4_ht2_spec = {
@@ -711,7 +705,8 @@ struct op_x86_model_spec const op_p4_ht2_spec = {
        .setup_ctrs = &p4_setup_ctrs,
        .check_ctrs = &p4_check_ctrs,
        .start = &p4_start,
-       .stop = &p4_stop
+       .stop = &p4_stop,
+       .shutdown = &p4_shutdown
 };
 #endif
 
@@ -722,5 +717,6 @@ struct op_x86_model_spec const op_p4_spec = {
        .setup_ctrs = &p4_setup_ctrs,
        .check_ctrs = &p4_check_ctrs,
        .start = &p4_start,
-       .stop = &p4_stop
+       .stop = &p4_stop,
+       .shutdown = &p4_shutdown
 };