root/arch/powerpc/oprofile/op_model_pa6t.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ctr_read
  2. ctr_write
  3. pa6t_reg_setup
  4. pa6t_cpu_setup
  5. pa6t_start
  6. pa6t_stop
  7. pa6t_handle_interrupt

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2006-2007 PA Semi, Inc
   4  *
   5  * Author: Shashi Rao, PA Semi
   6  *
   7  * Maintained by: Olof Johansson <olof@lixom.net>
   8  *
   9  * Based on arch/powerpc/oprofile/op_model_power4.c
  10  */
  11 
  12 #include <linux/oprofile.h>
  13 #include <linux/smp.h>
  14 #include <linux/percpu.h>
  15 #include <asm/processor.h>
  16 #include <asm/cputable.h>
  17 #include <asm/oprofile_impl.h>
  18 #include <asm/reg.h>
  19 
  20 static unsigned char oprofile_running;
  21 
  22 /* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */
  23 static u64 mmcr0_val;
  24 static u64 mmcr1_val;
  25 
  26 /* inited in pa6t_reg_setup */
  27 static u64 reset_value[OP_MAX_COUNTER];
  28 
  29 static inline u64 ctr_read(unsigned int i)
  30 {
  31         switch (i) {
  32         case 0:
  33                 return mfspr(SPRN_PA6T_PMC0);
  34         case 1:
  35                 return mfspr(SPRN_PA6T_PMC1);
  36         case 2:
  37                 return mfspr(SPRN_PA6T_PMC2);
  38         case 3:
  39                 return mfspr(SPRN_PA6T_PMC3);
  40         case 4:
  41                 return mfspr(SPRN_PA6T_PMC4);
  42         case 5:
  43                 return mfspr(SPRN_PA6T_PMC5);
  44         default:
  45                 printk(KERN_ERR "ctr_read called with bad arg %u\n", i);
  46                 return 0;
  47         }
  48 }
  49 
  50 static inline void ctr_write(unsigned int i, u64 val)
  51 {
  52         switch (i) {
  53         case 0:
  54                 mtspr(SPRN_PA6T_PMC0, val);
  55                 break;
  56         case 1:
  57                 mtspr(SPRN_PA6T_PMC1, val);
  58                 break;
  59         case 2:
  60                 mtspr(SPRN_PA6T_PMC2, val);
  61                 break;
  62         case 3:
  63                 mtspr(SPRN_PA6T_PMC3, val);
  64                 break;
  65         case 4:
  66                 mtspr(SPRN_PA6T_PMC4, val);
  67                 break;
  68         case 5:
  69                 mtspr(SPRN_PA6T_PMC5, val);
  70                 break;
  71         default:
  72                 printk(KERN_ERR "ctr_write called with bad arg %u\n", i);
  73                 break;
  74         }
  75 }
  76 
  77 
  78 /* precompute the values to stuff in the hardware registers */
  79 static int pa6t_reg_setup(struct op_counter_config *ctr,
  80                            struct op_system_config *sys,
  81                            int num_ctrs)
  82 {
  83         int pmc;
  84 
  85         /*
  86          * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the
  87          * event_mappings file by turning off the counters that the user doesn't
  88          * care about
  89          *
  90          * setup user and kernel profiling
  91          */
  92         for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++)
  93                 if (!ctr[pmc].enabled) {
  94                         sys->mmcr0 &= ~(0x1UL << pmc);
  95                         sys->mmcr0 &= ~(0x1UL << (pmc+12));
  96                         pr_debug("turned off counter %u\n", pmc);
  97                 }
  98 
  99         if (sys->enable_kernel)
 100                 sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN;
 101         else
 102                 sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN);
 103 
 104         if (sys->enable_user)
 105                 sys->mmcr0 |= PA6T_MMCR0_PREN;
 106         else
 107                 sys->mmcr0 &= ~PA6T_MMCR0_PREN;
 108 
 109         /*
 110          * The performance counter event settings are given in the mmcr0 and
 111          * mmcr1 values passed from the user in the op_system_config
 112          * structure (sys variable).
 113          */
 114         mmcr0_val = sys->mmcr0;
 115         mmcr1_val = sys->mmcr1;
 116         pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0);
 117         pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1);
 118 
 119         for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) {
 120                 /* counters are 40 bit. Move to cputable at some point? */
 121                 reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count;
 122                 pr_debug("reset_value for pmc%u inited to 0x%llx\n",
 123                                  pmc, reset_value[pmc]);
 124         }
 125 
 126         return 0;
 127 }
 128 
 129 /* configure registers on this cpu */
 130 static int pa6t_cpu_setup(struct op_counter_config *ctr)
 131 {
 132         u64 mmcr0 = mmcr0_val;
 133         u64 mmcr1 = mmcr1_val;
 134 
 135         /* Default is all PMCs off */
 136         mmcr0 &= ~(0x3FUL);
 137         mtspr(SPRN_PA6T_MMCR0, mmcr0);
 138 
 139         /* program selected programmable events in */
 140         mtspr(SPRN_PA6T_MMCR1, mmcr1);
 141 
 142         pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(),
 143                 mfspr(SPRN_PA6T_MMCR0));
 144         pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
 145                 mfspr(SPRN_PA6T_MMCR1));
 146 
 147         return 0;
 148 }
 149 
 150 static int pa6t_start(struct op_counter_config *ctr)
 151 {
 152         int i;
 153 
 154         /* Hold off event counting until rfid */
 155         u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
 156 
 157         for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
 158                 if (ctr[i].enabled)
 159                         ctr_write(i, reset_value[i]);
 160                 else
 161                         ctr_write(i, 0UL);
 162 
 163         mtspr(SPRN_PA6T_MMCR0, mmcr0);
 164 
 165         oprofile_running = 1;
 166 
 167         pr_debug("start on cpu %d, mmcr0 %llx\n", smp_processor_id(), mmcr0);
 168 
 169         return 0;
 170 }
 171 
 172 static void pa6t_stop(void)
 173 {
 174         u64 mmcr0;
 175 
 176         /* freeze counters */
 177         mmcr0 = mfspr(SPRN_PA6T_MMCR0);
 178         mmcr0 |= PA6T_MMCR0_FCM0;
 179         mtspr(SPRN_PA6T_MMCR0, mmcr0);
 180 
 181         oprofile_running = 0;
 182 
 183         pr_debug("stop on cpu %d, mmcr0 %llx\n", smp_processor_id(), mmcr0);
 184 }
 185 
 186 /* handle the perfmon overflow vector */
 187 static void pa6t_handle_interrupt(struct pt_regs *regs,
 188                                   struct op_counter_config *ctr)
 189 {
 190         unsigned long pc = mfspr(SPRN_PA6T_SIAR);
 191         int is_kernel = is_kernel_addr(pc);
 192         u64 val;
 193         int i;
 194         u64 mmcr0;
 195 
 196         /* disable perfmon counting until rfid */
 197         mmcr0 = mfspr(SPRN_PA6T_MMCR0);
 198         mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS);
 199 
 200         /* Record samples. We've got one global bit for whether a sample
 201          * was taken, so add it for any counter that triggered overflow.
 202          */
 203         for (i = 0; i < cur_cpu_spec->num_pmcs; i++) {
 204                 val = ctr_read(i);
 205                 if (val & (0x1UL << 39)) { /* Overflow bit set */
 206                         if (oprofile_running && ctr[i].enabled) {
 207                                 if (mmcr0 & PA6T_MMCR0_SIARLOG)
 208                                         oprofile_add_ext_sample(pc, regs, i, is_kernel);
 209                                 ctr_write(i, reset_value[i]);
 210                         } else {
 211                                 ctr_write(i, 0UL);
 212                         }
 213                 }
 214         }
 215 
 216         /* Restore mmcr0 to a good known value since the PMI changes it */
 217         mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
 218         mtspr(SPRN_PA6T_MMCR0, mmcr0);
 219 }
 220 
 221 struct op_powerpc_model op_model_pa6t = {
 222         .reg_setup              = pa6t_reg_setup,
 223         .cpu_setup              = pa6t_cpu_setup,
 224         .start                  = pa6t_start,
 225         .stop                   = pa6t_stop,
 226         .handle_interrupt       = pa6t_handle_interrupt,
 227 };

/* [<][>][^][v][top][bottom][index][help] */