linux/arch/powerpc/oprofile/common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * PPC 64 oprofile support:
   4 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
   5 * PPC 32 oprofile support: (based on PPC 64 support)
   6 * Copyright (C) Freescale Semiconductor, Inc 2004
   7 *      Author: Andy Fleming
   8 *
   9 * Based on alpha version.
  10 */
  11
  12#include <linux/oprofile.h>
  13#include <linux/init.h>
  14#include <linux/smp.h>
  15#include <linux/errno.h>
  16#include <asm/ptrace.h>
  17#include <asm/pmc.h>
  18#include <asm/cputable.h>
  19#include <asm/oprofile_impl.h>
  20#include <asm/firmware.h>
  21
  22static struct op_powerpc_model *model;
  23
  24static struct op_counter_config ctr[OP_MAX_COUNTER];
  25static struct op_system_config sys;
  26
  27static int op_per_cpu_rc;
  28
  29static void op_handle_interrupt(struct pt_regs *regs)
  30{
  31        model->handle_interrupt(regs, ctr);
  32}
  33
  34static void op_powerpc_cpu_setup(void *dummy)
  35{
  36        int ret;
  37
  38        ret = model->cpu_setup(ctr);
  39
  40        if (ret != 0)
  41                op_per_cpu_rc = ret;
  42}
  43
  44static int op_powerpc_setup(void)
  45{
  46        int err;
  47
  48        op_per_cpu_rc = 0;
  49
  50        /* Grab the hardware */
  51        err = reserve_pmc_hardware(op_handle_interrupt);
  52        if (err)
  53                return err;
  54
  55        /* Pre-compute the values to stuff in the hardware registers.  */
  56        op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
  57
  58        if (op_per_cpu_rc)
  59                goto out;
  60
  61        /* Configure the registers on all cpus.  If an error occurs on one
  62         * of the cpus, op_per_cpu_rc will be set to the error */
  63        on_each_cpu(op_powerpc_cpu_setup, NULL, 1);
  64
  65out:    if (op_per_cpu_rc) {
  66                /* error on setup release the performance counter hardware */
  67                release_pmc_hardware();
  68        }
  69
  70        return op_per_cpu_rc;
  71}
  72
  73static void op_powerpc_shutdown(void)
  74{
  75        release_pmc_hardware();
  76}
  77
  78static void op_powerpc_cpu_start(void *dummy)
  79{
  80        /* If any of the cpus have return an error, set the
  81         * global flag to the error so it can be returned
  82         * to the generic OProfile caller.
  83         */
  84        int ret;
  85
  86        ret = model->start(ctr);
  87        if (ret != 0)
  88                op_per_cpu_rc = ret;
  89}
  90
  91static int op_powerpc_start(void)
  92{
  93        op_per_cpu_rc = 0;
  94
  95        if (model->global_start)
  96                return model->global_start(ctr);
  97        if (model->start) {
  98                on_each_cpu(op_powerpc_cpu_start, NULL, 1);
  99                return op_per_cpu_rc;
 100        }
 101        return -EIO; /* No start function is defined for this
 102                        power architecture */
 103}
 104
 105static inline void op_powerpc_cpu_stop(void *dummy)
 106{
 107        model->stop();
 108}
 109
 110static void op_powerpc_stop(void)
 111{
 112        if (model->stop)
 113                on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
 114        if (model->global_stop)
 115                model->global_stop();
 116}
 117
 118static int op_powerpc_create_files(struct dentry *root)
 119{
 120        int i;
 121
 122#ifdef CONFIG_PPC64
 123        /*
 124         * There is one mmcr0, mmcr1 and mmcra for setting the events for
 125         * all of the counters.
 126         */
 127        oprofilefs_create_ulong(root, "mmcr0", &sys.mmcr0);
 128        oprofilefs_create_ulong(root, "mmcr1", &sys.mmcr1);
 129        oprofilefs_create_ulong(root, "mmcra", &sys.mmcra);
 130#ifdef CONFIG_OPROFILE_CELL
 131        /* create a file the user tool can check to see what level of profiling
 132         * support exits with this kernel. Initialize bit mask to indicate
 133         * what support the kernel has:
 134         * bit 0      -  Supports SPU event profiling in addition to PPU
 135         *               event and cycles; and SPU cycle profiling
 136         * bits 1-31  -  Currently unused.
 137         *
 138         * If the file does not exist, then the kernel only supports SPU
 139         * cycle profiling, PPU event and cycle profiling.
 140         */
 141        oprofilefs_create_ulong(root, "cell_support", &sys.cell_support);
 142        sys.cell_support = 0x1; /* Note, the user OProfile tool must check
 143                                 * that this bit is set before attempting to
 144                                 * user SPU event profiling.  Older kernels
 145                                 * will not have this file, hence the user
 146                                 * tool is not allowed to do SPU event
 147                                 * profiling on older kernels.  Older kernels
 148                                 * will accept SPU events but collected data
 149                                 * is garbage.
 150                                 */
 151#endif
 152#endif
 153
 154        for (i = 0; i < model->num_counters; ++i) {
 155                struct dentry *dir;
 156                char buf[4];
 157
 158                snprintf(buf, sizeof buf, "%d", i);
 159                dir = oprofilefs_mkdir(root, buf);
 160
 161                oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled);
 162                oprofilefs_create_ulong(dir, "event", &ctr[i].event);
 163                oprofilefs_create_ulong(dir, "count", &ctr[i].count);
 164
 165                /*
 166                 * Classic PowerPC doesn't support per-counter
 167                 * control like this, but the options are
 168                 * expected, so they remain.  For Freescale
 169                 * Book-E style performance monitors, we do
 170                 * support them.
 171                 */
 172                oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
 173                oprofilefs_create_ulong(dir, "user", &ctr[i].user);
 174
 175                oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
 176        }
 177
 178        oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel);
 179        oprofilefs_create_ulong(root, "enable_user", &sys.enable_user);
 180
 181        /* Default to tracing both kernel and user */
 182        sys.enable_kernel = 1;
 183        sys.enable_user = 1;
 184
 185        return 0;
 186}
 187
 188int __init oprofile_arch_init(struct oprofile_operations *ops)
 189{
 190        if (!cur_cpu_spec->oprofile_cpu_type)
 191                return -ENODEV;
 192
 193        switch (cur_cpu_spec->oprofile_type) {
 194#ifdef CONFIG_PPC_BOOK3S_64
 195#ifdef CONFIG_OPROFILE_CELL
 196                case PPC_OPROFILE_CELL:
 197                        if (firmware_has_feature(FW_FEATURE_LPAR))
 198                                return -ENODEV;
 199                        model = &op_model_cell;
 200                        ops->sync_start = model->sync_start;
 201                        ops->sync_stop = model->sync_stop;
 202                        break;
 203#endif
 204                case PPC_OPROFILE_POWER4:
 205                        model = &op_model_power4;
 206                        break;
 207                case PPC_OPROFILE_PA6T:
 208                        model = &op_model_pa6t;
 209                        break;
 210#endif
 211#ifdef CONFIG_PPC_BOOK3S_32
 212                case PPC_OPROFILE_G4:
 213                        model = &op_model_7450;
 214                        break;
 215#endif
 216#if defined(CONFIG_FSL_EMB_PERFMON)
 217                case PPC_OPROFILE_FSL_EMB:
 218                        model = &op_model_fsl_emb;
 219                        break;
 220#endif
 221                default:
 222                        return -ENODEV;
 223        }
 224
 225        model->num_counters = cur_cpu_spec->num_pmcs;
 226
 227        ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
 228        ops->create_files = op_powerpc_create_files;
 229        ops->setup = op_powerpc_setup;
 230        ops->shutdown = op_powerpc_shutdown;
 231        ops->start = op_powerpc_start;
 232        ops->stop = op_powerpc_stop;
 233        ops->backtrace = op_powerpc_backtrace;
 234
 235        printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
 236               ops->cpu_type);
 237
 238        return 0;
 239}
 240
 241void oprofile_arch_exit(void)
 242{
 243}
 244