fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / powerpc / oprofile / op_model_power4.c
index 4c2beab..356709d 100644 (file)
 static unsigned long reset_value[OP_MAX_COUNTER];
 
 static int oprofile_running;
-static int mmcra_has_sihv;
-/* Unfortunately these bits vary between CPUs */
-static unsigned long mmcra_sihv = MMCRA_SIHV;
-static unsigned long mmcra_sipr = MMCRA_SIPR;
 
 /* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */
 static u32 mmcr0_val;
@@ -40,16 +36,6 @@ static void power4_reg_setup(struct op_counter_config *ctr,
 {
        int i;
 
-       /*
-        * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above.
-        * However we disable it on all POWER4 until we verify it works
-        * (I was seeing some strange behaviour last time I tried).
-        *
-        * It has been verified to work on POWER5 so we enable it there.
-        */
-       if (cpu_has_feature(CPU_FTR_MMCRA_SIHV))
-               mmcra_has_sihv = 1;
-
        /*
         * The performance counter event settings are given in the mmcr0,
         * mmcr1 and mmcra values passed from the user in the
@@ -90,13 +76,13 @@ static inline int mmcra_must_set_sample(void)
 {
        if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) ||
            __is_processor(PV_970) || __is_processor(PV_970FX) ||
-           __is_processor(PV_970MP))
+           __is_processor(PV_970MP) || __is_processor(PV_970GX))
                return 1;
 
        return 0;
 }
 
-static void power4_cpu_setup(void *unused)
+static void power4_cpu_setup(struct op_counter_config *ctr)
 {
        unsigned int mmcr0 = mmcr0_val;
        unsigned long mmcra = mmcra_val;
@@ -202,18 +188,19 @@ static unsigned long get_pc(struct pt_regs *regs)
        unsigned long mmcra;
 
        /* Cant do much about it */
-       if (!mmcra_has_sihv)
+       if (!cur_cpu_spec->oprofile_mmcra_sihv)
                return pc;
 
        mmcra = mfspr(SPRN_MMCRA);
 
        /* Were we in the hypervisor? */
-       if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & mmcra_sihv))
+       if (firmware_has_feature(FW_FEATURE_LPAR) &&
+           (mmcra & cur_cpu_spec->oprofile_mmcra_sihv))
                /* function descriptor madness */
                return *((unsigned long *)hypervisor_bucket);
 
        /* We were in userspace, nothing to do */
-       if (mmcra & mmcra_sipr)
+       if (mmcra & cur_cpu_spec->oprofile_mmcra_sipr)
                return pc;
 
 #ifdef CONFIG_PPC_RTAS
@@ -235,15 +222,14 @@ static unsigned long get_pc(struct pt_regs *regs)
        return pc;
 }
 
-static int get_kernel(unsigned long pc)
+static int get_kernel(unsigned long pc, unsigned long mmcra)
 {
        int is_kernel;
 
-       if (!mmcra_has_sihv) {
+       if (!cur_cpu_spec->oprofile_mmcra_sihv) {
                is_kernel = is_kernel_addr(pc);
        } else {
-               unsigned long mmcra = mfspr(SPRN_MMCRA);
-               is_kernel = ((mmcra & mmcra_sipr) == 0);
+               is_kernel = ((mmcra & cur_cpu_spec->oprofile_mmcra_sipr) == 0);
        }
 
        return is_kernel;
@@ -257,9 +243,12 @@ static void power4_handle_interrupt(struct pt_regs *regs,
        int val;
        int i;
        unsigned int mmcr0;
+       unsigned long mmcra;
+
+       mmcra = mfspr(SPRN_MMCRA);
 
        pc = get_pc(regs);
-       is_kernel = get_kernel(pc);
+       is_kernel = get_kernel(pc, mmcra);
 
        /* set the PMM bit (see comment below) */
        mtmsrd(mfmsr() | MSR_PMM);
@@ -287,6 +276,10 @@ static void power4_handle_interrupt(struct pt_regs *regs,
         */
        mmcr0 &= ~MMCR0_PMAO;
 
+       /* Clear the appropriate bits in the MMCRA */
+       mmcra &= ~cur_cpu_spec->oprofile_mmcra_clear;
+       mtspr(SPRN_MMCRA, mmcra);
+
        /*
         * now clear the freeze bit, counting will not start until we
         * rfid from this exception, because only at that point will