linux/drivers/misc/sgi-gru/gruprocfs.c
<<
>>
Prefs
   1/*
   2 * SN Platform GRU Driver
   3 *
   4 *              PROC INTERFACES
   5 *
   6 * This file supports the /proc interfaces for the GRU driver
   7 *
   8 *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License as published by
  12 *  the Free Software Foundation; either version 2 of the License, or
  13 *  (at your option) any later version.
  14 *
  15 *  This program is distributed in the hope that it will be useful,
  16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 *  GNU General Public License for more details.
  19 *
  20 *  You should have received a copy of the GNU General Public License
  21 *  along with this program; if not, write to the Free Software
  22 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  23 */
  24
  25#include <linux/proc_fs.h>
  26#include <linux/device.h>
  27#include <linux/seq_file.h>
  28#include <linux/uaccess.h>
  29#include "gru.h"
  30#include "grulib.h"
  31#include "grutables.h"
  32
  33#define printstat(s, f)         printstat_val(s, &gru_stats.f, #f)
  34
  35static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id)
  36{
  37        unsigned long val = atomic_long_read(v);
  38
  39        if (val)
  40                seq_printf(s, "%16lu %s\n", val, id);
  41}
  42
  43static int statistics_show(struct seq_file *s, void *p)
  44{
  45        printstat(s, vdata_alloc);
  46        printstat(s, vdata_free);
  47        printstat(s, gts_alloc);
  48        printstat(s, gts_free);
  49        printstat(s, vdata_double_alloc);
  50        printstat(s, gts_double_allocate);
  51        printstat(s, assign_context);
  52        printstat(s, assign_context_failed);
  53        printstat(s, free_context);
  54        printstat(s, load_context);
  55        printstat(s, unload_context);
  56        printstat(s, steal_context);
  57        printstat(s, steal_context_failed);
  58        printstat(s, nopfn);
  59        printstat(s, break_cow);
  60        printstat(s, asid_new);
  61        printstat(s, asid_next);
  62        printstat(s, asid_wrap);
  63        printstat(s, asid_reuse);
  64        printstat(s, intr);
  65        printstat(s, call_os);
  66        printstat(s, call_os_check_for_bug);
  67        printstat(s, call_os_wait_queue);
  68        printstat(s, user_flush_tlb);
  69        printstat(s, user_unload_context);
  70        printstat(s, user_exception);
  71        printstat(s, set_task_slice);
  72        printstat(s, migrate_check);
  73        printstat(s, migrated_retarget);
  74        printstat(s, migrated_unload);
  75        printstat(s, migrated_unload_delay);
  76        printstat(s, migrated_nopfn_retarget);
  77        printstat(s, migrated_nopfn_unload);
  78        printstat(s, tlb_dropin);
  79        printstat(s, tlb_dropin_fail_no_asid);
  80        printstat(s, tlb_dropin_fail_upm);
  81        printstat(s, tlb_dropin_fail_invalid);
  82        printstat(s, tlb_dropin_fail_range_active);
  83        printstat(s, tlb_dropin_fail_idle);
  84        printstat(s, tlb_dropin_fail_fmm);
  85        printstat(s, mmu_invalidate_range);
  86        printstat(s, mmu_invalidate_page);
  87        printstat(s, mmu_clear_flush_young);
  88        printstat(s, flush_tlb);
  89        printstat(s, flush_tlb_gru);
  90        printstat(s, flush_tlb_gru_tgh);
  91        printstat(s, flush_tlb_gru_zero_asid);
  92        printstat(s, copy_gpa);
  93        printstat(s, mesq_receive);
  94        printstat(s, mesq_receive_none);
  95        printstat(s, mesq_send);
  96        printstat(s, mesq_send_failed);
  97        printstat(s, mesq_noop);
  98        printstat(s, mesq_send_unexpected_error);
  99        printstat(s, mesq_send_lb_overflow);
 100        printstat(s, mesq_send_qlimit_reached);
 101        printstat(s, mesq_send_amo_nacked);
 102        printstat(s, mesq_send_put_nacked);
 103        printstat(s, mesq_qf_not_full);
 104        printstat(s, mesq_qf_locked);
 105        printstat(s, mesq_qf_noop_not_full);
 106        printstat(s, mesq_qf_switch_head_failed);
 107        printstat(s, mesq_qf_unexpected_error);
 108        printstat(s, mesq_noop_unexpected_error);
 109        printstat(s, mesq_noop_lb_overflow);
 110        printstat(s, mesq_noop_qlimit_reached);
 111        printstat(s, mesq_noop_amo_nacked);
 112        printstat(s, mesq_noop_put_nacked);
 113        return 0;
 114}
 115
 116static ssize_t statistics_write(struct file *file, const char __user *userbuf,
 117                                size_t count, loff_t *data)
 118{
 119        memset(&gru_stats, 0, sizeof(gru_stats));
 120        return count;
 121}
 122
 123static int options_show(struct seq_file *s, void *p)
 124{
 125        seq_printf(s, "0x%lx\n", gru_options);
 126        return 0;
 127}
 128
 129static ssize_t options_write(struct file *file, const char __user *userbuf,
 130                             size_t count, loff_t *data)
 131{
 132        unsigned long val;
 133        char buf[80];
 134
 135        if (copy_from_user
 136            (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
 137                return -EFAULT;
 138        if (!strict_strtoul(buf, 10, &val))
 139                gru_options = val;
 140
 141        return count;
 142}
 143
 144static int cch_seq_show(struct seq_file *file, void *data)
 145{
 146        long gid = *(long *)data;
 147        int i;
 148        struct gru_state *gru = GID_TO_GRU(gid);
 149        struct gru_thread_state *ts;
 150        const char *mode[] = { "??", "UPM", "INTR", "OS_POLL" };
 151
 152        if (gid == 0)
 153                seq_printf(file, "#%5s%5s%6s%9s%6s%8s%8s\n", "gid", "bid",
 154                           "ctx#", "pid", "cbrs", "dsbytes", "mode");
 155        if (gru)
 156                for (i = 0; i < GRU_NUM_CCH; i++) {
 157                        ts = gru->gs_gts[i];
 158                        if (!ts)
 159                                continue;
 160                        seq_printf(file, " %5d%5d%6d%9d%6d%8d%8s\n",
 161                                   gru->gs_gid, gru->gs_blade_id, i,
 162                                   ts->ts_tgid_owner,
 163                                   ts->ts_cbr_au_count * GRU_CBR_AU_SIZE,
 164                                   ts->ts_cbr_au_count * GRU_DSR_AU_BYTES,
 165                                   mode[ts->ts_user_options &
 166                                        GRU_OPT_MISS_MASK]);
 167                }
 168
 169        return 0;
 170}
 171
 172static int gru_seq_show(struct seq_file *file, void *data)
 173{
 174        long gid = *(long *)data, ctxfree, cbrfree, dsrfree;
 175        struct gru_state *gru = GID_TO_GRU(gid);
 176
 177        if (gid == 0) {
 178                seq_printf(file, "#%5s%5s%7s%6s%6s%8s%6s%6s\n", "gid", "nid",
 179                           "ctx", "cbr", "dsr", "ctx", "cbr", "dsr");
 180                seq_printf(file, "#%5s%5s%7s%6s%6s%8s%6s%6s\n", "", "", "busy",
 181                           "busy", "busy", "free", "free", "free");
 182        }
 183        if (gru) {
 184                ctxfree = GRU_NUM_CCH - gru->gs_active_contexts;
 185                cbrfree = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE;
 186                dsrfree = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES;
 187                seq_printf(file, " %5d%5d%7ld%6ld%6ld%8ld%6ld%6ld\n",
 188                           gru->gs_gid, gru->gs_blade_id, GRU_NUM_CCH - ctxfree,
 189                           GRU_NUM_CBE - cbrfree, GRU_NUM_DSR_BYTES - dsrfree,
 190                           ctxfree, cbrfree, dsrfree);
 191        }
 192
 193        return 0;
 194}
 195
 196static void seq_stop(struct seq_file *file, void *data)
 197{
 198}
 199
 200static void *seq_start(struct seq_file *file, loff_t *gid)
 201{
 202        if (*gid < GRU_MAX_GRUS)
 203                return gid;
 204        return NULL;
 205}
 206
 207static void *seq_next(struct seq_file *file, void *data, loff_t *gid)
 208{
 209        (*gid)++;
 210        if (*gid < GRU_MAX_GRUS)
 211                return gid;
 212        return NULL;
 213}
 214
 215static const struct seq_operations cch_seq_ops = {
 216        .start  = seq_start,
 217        .next   = seq_next,
 218        .stop   = seq_stop,
 219        .show   = cch_seq_show
 220};
 221
 222static const struct seq_operations gru_seq_ops = {
 223        .start  = seq_start,
 224        .next   = seq_next,
 225        .stop   = seq_stop,
 226        .show   = gru_seq_show
 227};
 228
 229static int statistics_open(struct inode *inode, struct file *file)
 230{
 231        return single_open(file, statistics_show, NULL);
 232}
 233
 234static int options_open(struct inode *inode, struct file *file)
 235{
 236        return single_open(file, options_show, NULL);
 237}
 238
 239static int cch_open(struct inode *inode, struct file *file)
 240{
 241        return seq_open(file, &cch_seq_ops);
 242}
 243
 244static int gru_open(struct inode *inode, struct file *file)
 245{
 246        return seq_open(file, &gru_seq_ops);
 247}
 248
 249/* *INDENT-OFF* */
 250static const struct file_operations statistics_fops = {
 251        .open           = statistics_open,
 252        .read           = seq_read,
 253        .write          = statistics_write,
 254        .llseek         = seq_lseek,
 255        .release        = single_release,
 256};
 257
 258static const struct file_operations options_fops = {
 259        .open           = options_open,
 260        .read           = seq_read,
 261        .write          = options_write,
 262        .llseek         = seq_lseek,
 263        .release        = single_release,
 264};
 265
 266static const struct file_operations cch_fops = {
 267        .open           = cch_open,
 268        .read           = seq_read,
 269        .llseek         = seq_lseek,
 270        .release        = seq_release,
 271};
 272static const struct file_operations gru_fops = {
 273        .open           = gru_open,
 274        .read           = seq_read,
 275        .llseek         = seq_lseek,
 276        .release        = seq_release,
 277};
 278
 279static struct proc_entry {
 280        char *name;
 281        int mode;
 282        const struct file_operations *fops;
 283        struct proc_dir_entry *entry;
 284} proc_files[] = {
 285        {"statistics", 0644, &statistics_fops},
 286        {"debug_options", 0644, &options_fops},
 287        {"cch_status", 0444, &cch_fops},
 288        {"gru_status", 0444, &gru_fops},
 289        {NULL}
 290};
 291/* *INDENT-ON* */
 292
 293static struct proc_dir_entry *proc_gru __read_mostly;
 294
 295static int create_proc_file(struct proc_entry *p)
 296{
 297        p->entry = create_proc_entry(p->name, p->mode, proc_gru);
 298        if (!p->entry)
 299                return -1;
 300        p->entry->proc_fops = p->fops;
 301        return 0;
 302}
 303
 304static void delete_proc_files(void)
 305{
 306        struct proc_entry *p;
 307
 308        if (proc_gru) {
 309                for (p = proc_files; p->name; p++)
 310                        if (p->entry)
 311                                remove_proc_entry(p->name, proc_gru);
 312                remove_proc_entry("gru", NULL);
 313        }
 314}
 315
 316int gru_proc_init(void)
 317{
 318        struct proc_entry *p;
 319
 320        proc_mkdir("sgi_uv", NULL);
 321        proc_gru = proc_mkdir("sgi_uv/gru", NULL);
 322
 323        for (p = proc_files; p->name; p++)
 324                if (create_proc_file(p))
 325                        goto err;
 326        return 0;
 327
 328err:
 329        delete_proc_files();
 330        return -1;
 331}
 332
 333void gru_proc_exit(void)
 334{
 335        delete_proc_files();
 336}
 337