linux/arch/s390/oprofile/init.c
<<
>>
Prefs
   1/**
   2 * arch/s390/oprofile/init.c
   3 *
   4 * S390 Version
   5 *   Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
   7 *   Author(s): Mahesh Salgaonkar (mahesh@linux.vnet.ibm.com)
   8 *   Author(s): Heinz Graalfs (graalfs@linux.vnet.ibm.com)
   9 *
  10 * @remark Copyright 2002-2011 OProfile authors
  11 */
  12
  13#include <linux/oprofile.h>
  14#include <linux/init.h>
  15#include <linux/errno.h>
  16#include <linux/oprofile.h>
  17#include <linux/errno.h>
  18#include <linux/fs.h>
  19
  20#include "../../../drivers/oprofile/oprof.h"
  21
  22extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
  23
  24#ifdef CONFIG_64BIT
  25
  26#include "hwsampler.h"
  27
  28#define DEFAULT_INTERVAL        4096
  29
  30#define DEFAULT_SDBT_BLOCKS     1
  31#define DEFAULT_SDB_BLOCKS      511
  32
  33static unsigned long oprofile_hw_interval = DEFAULT_INTERVAL;
  34static unsigned long oprofile_min_interval;
  35static unsigned long oprofile_max_interval;
  36
  37static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS;
  38static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS;
  39
  40static int hwsampler_file;
  41static int hwsampler_running;   /* start_mutex must be held to change */
  42
  43static struct oprofile_operations timer_ops;
  44
  45static int oprofile_hwsampler_start(void)
  46{
  47        int retval;
  48
  49        hwsampler_running = hwsampler_file;
  50
  51        if (!hwsampler_running)
  52                return timer_ops.start();
  53
  54        retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
  55        if (retval)
  56                return retval;
  57
  58        retval = hwsampler_start_all(oprofile_hw_interval);
  59        if (retval)
  60                hwsampler_deallocate();
  61
  62        return retval;
  63}
  64
  65static void oprofile_hwsampler_stop(void)
  66{
  67        if (!hwsampler_running) {
  68                timer_ops.stop();
  69                return;
  70        }
  71
  72        hwsampler_stop_all();
  73        hwsampler_deallocate();
  74        return;
  75}
  76
  77static ssize_t hwsampler_read(struct file *file, char __user *buf,
  78                size_t count, loff_t *offset)
  79{
  80        return oprofilefs_ulong_to_user(hwsampler_file, buf, count, offset);
  81}
  82
  83static ssize_t hwsampler_write(struct file *file, char const __user *buf,
  84                size_t count, loff_t *offset)
  85{
  86        unsigned long val;
  87        int retval;
  88
  89        if (*offset)
  90                return -EINVAL;
  91
  92        retval = oprofilefs_ulong_from_user(&val, buf, count);
  93        if (retval)
  94                return retval;
  95
  96        if (oprofile_started)
  97                /*
  98                 * save to do without locking as we set
  99                 * hwsampler_running in start() when start_mutex is
 100                 * held
 101                 */
 102                return -EBUSY;
 103
 104        hwsampler_file = val;
 105
 106        return count;
 107}
 108
 109static const struct file_operations hwsampler_fops = {
 110        .read           = hwsampler_read,
 111        .write          = hwsampler_write,
 112};
 113
 114static int oprofile_create_hwsampling_files(struct super_block *sb,
 115                                                struct dentry *root)
 116{
 117        struct dentry *hw_dir;
 118
 119        /* reinitialize default values */
 120        hwsampler_file = 1;
 121
 122        hw_dir = oprofilefs_mkdir(sb, root, "hwsampling");
 123        if (!hw_dir)
 124                return -EINVAL;
 125
 126        oprofilefs_create_file(sb, hw_dir, "hwsampler", &hwsampler_fops);
 127        oprofilefs_create_ulong(sb, hw_dir, "hw_interval",
 128                                &oprofile_hw_interval);
 129        oprofilefs_create_ro_ulong(sb, hw_dir, "hw_min_interval",
 130                                &oprofile_min_interval);
 131        oprofilefs_create_ro_ulong(sb, hw_dir, "hw_max_interval",
 132                                &oprofile_max_interval);
 133        oprofilefs_create_ulong(sb, hw_dir, "hw_sdbt_blocks",
 134                                &oprofile_sdbt_blocks);
 135
 136        return 0;
 137}
 138
 139static int oprofile_hwsampler_init(struct oprofile_operations *ops)
 140{
 141        if (hwsampler_setup())
 142                return -ENODEV;
 143
 144        /*
 145         * create hwsampler files only if hwsampler_setup() succeeds.
 146         */
 147        oprofile_min_interval = hwsampler_query_min_interval();
 148        if (oprofile_min_interval == 0)
 149                return -ENODEV;
 150        oprofile_max_interval = hwsampler_query_max_interval();
 151        if (oprofile_max_interval == 0)
 152                return -ENODEV;
 153
 154        if (oprofile_timer_init(ops))
 155                return -ENODEV;
 156
 157        printk(KERN_INFO "oprofile: using hardware sampling\n");
 158
 159        memcpy(&timer_ops, ops, sizeof(timer_ops));
 160
 161        ops->start = oprofile_hwsampler_start;
 162        ops->stop = oprofile_hwsampler_stop;
 163        ops->create_files = oprofile_create_hwsampling_files;
 164
 165        return 0;
 166}
 167
 168static void oprofile_hwsampler_exit(void)
 169{
 170        oprofile_timer_exit();
 171        hwsampler_shutdown();
 172}
 173
 174#endif /* CONFIG_64BIT */
 175
 176int __init oprofile_arch_init(struct oprofile_operations *ops)
 177{
 178        ops->backtrace = s390_backtrace;
 179
 180#ifdef CONFIG_64BIT
 181        return oprofile_hwsampler_init(ops);
 182#else
 183        return -ENODEV;
 184#endif
 185}
 186
 187void oprofile_arch_exit(void)
 188{
 189#ifdef CONFIG_64BIT
 190        oprofile_hwsampler_exit();
 191#endif
 192}
 193