linux-old/arch/ppc64/kernel/proc_pmc.c
<<
>>
Prefs
   1/*
   2 * proc_pmc.c
   3 * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
   4 * 
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 * 
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 * 
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18 */
  19
  20
  21/* Change Activity:
  22 * 2001       : mikec    : Created
  23 * 2001/06/05 : engebret : Software event count support.
  24 * 2001/08/03 : trautman : Added PCI Flight Recorder
  25 * End Change Activity 
  26 */
  27
  28#include <asm/proc_fs.h>
  29#include <asm/paca.h>
  30#include <asm/iSeries/ItLpPaca.h>
  31#include <asm/iSeries/ItLpQueue.h>
  32#include <asm/iSeries/HvCallXm.h>
  33#include <asm/iSeries/IoHriMainStore.h>
  34#include <asm/processor.h>
  35#include <asm/time.h>
  36#include <asm/iSeries/LparData.h>
  37
  38#include <linux/config.h>
  39#include <linux/proc_fs.h>
  40#include <linux/spinlock.h>
  41#include <asm/pmc.h>
  42#include <asm/uaccess.h>
  43#include <asm/naca.h>
  44#include <asm/rtas.h>
  45#include <asm/perfmon.h>
  46
  47/* pci Flight Recorder AHT */
  48extern void proc_pciFr_init(struct proc_dir_entry *proc_ppc64_root);
  49
  50static int proc_pmc_control_mode = 0;
  51
  52struct proc_dir_entry *proc_ppc64_root = NULL;
  53static struct proc_dir_entry *proc_ppc64_pmc_root = NULL;
  54static struct proc_dir_entry *proc_ppc64_pmc_system_root = NULL;
  55static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, };
  56
  57spinlock_t proc_ppc64_lock;
  58static int proc_ppc64_page_read(char *page, char **start, off_t off,
  59                                int count, int *eof, void *data);
  60static void proc_ppc64_create_paca(int num, struct proc_dir_entry *paca_dir);
  61void proc_ppc64_create_smt(void);
  62
  63int proc_ppc64_pmc_find_file(void *data);
  64int proc_ppc64_pmc_read(char *page, char **start, off_t off,
  65                        int count, int *eof, char *buffer);
  66int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off,
  67                             int count, int *eof, void *data);
  68int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
  69                             int count, int *eof, void *data);
  70int proc_ppc64_pmc_profile_read(char *page, char **start, off_t off,
  71                                int count, int *eof, void *data);
  72int proc_ppc64_pmc_profile_read(char *page, char **start, off_t off,
  73                                int count, int *eof, void *data);
  74int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
  75                           int count, int *eof, void *data);
  76
  77static struct proc_dir_entry *pmc_proc_root = NULL;
  78
  79int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data);
  80int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data);
  81
  82int proc_get_titanTod( char *page, char **start, off_t off, int count, int *eof, void *data);
  83
  84int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data);
  85
  86int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data);
  87int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data);
  88int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data);
  89int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data);
  90int proc_pmc_set_pmc1(  struct file *file, const char *buffer, unsigned long count, void *data);
  91int proc_pmc_set_pmc2(  struct file *file, const char *buffer, unsigned long count, void *data);
  92int proc_pmc_set_pmc3(  struct file *file, const char *buffer, unsigned long count, void *data);
  93int proc_pmc_set_pmc4(  struct file *file, const char *buffer, unsigned long count, void *data);
  94int proc_pmc_set_pmc5(  struct file *file, const char *buffer, unsigned long count, void *data);
  95int proc_pmc_set_pmc6(  struct file *file, const char *buffer, unsigned long count, void *data);
  96int proc_pmc_set_pmc7(  struct file *file, const char *buffer, unsigned long count, void *data);
  97int proc_pmc_set_pmc8(  struct file *file, const char *buffer, unsigned long count, void *data);
  98
  99static loff_t  nacamap_seek( struct file *file, loff_t off, int whence);
 100static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
 101static int     nacamap_mmap( struct file *file, struct vm_area_struct *vma );
 102
 103static struct file_operations nacamap_fops = {
 104        llseek: nacamap_seek,
 105        read:   nacamap_read,
 106        mmap:   nacamap_mmap
 107};
 108
 109static ssize_t read_profile(struct file *file, char *buf, size_t count, loff_t *ppos);
 110static ssize_t write_profile(struct file * file, const char * buf,
 111                             size_t count, loff_t *ppos);
 112static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos);
 113static ssize_t write_trace(struct file * file, const char * buf,
 114                             size_t count, loff_t *ppos);
 115static ssize_t read_timeslice(struct file *file, char *buf, size_t count, loff_t *ppos);
 116static ssize_t write_timeslice(struct file * file, const char * buf,
 117                             size_t count, loff_t *ppos);
 118
 119static struct file_operations proc_profile_operations = {
 120        read:           read_profile,
 121        write:          write_profile,
 122};
 123
 124static struct file_operations proc_trace_operations = {
 125        read:           read_trace,
 126        write:          write_trace,
 127};
 128
 129static struct file_operations proc_timeslice_operations = {
 130        read:           read_timeslice,
 131        write:          write_timeslice,
 132};
 133
 134extern struct perfmon_base_struct perfmon_base;
 135
 136void proc_ppc64_init(void)
 137{
 138        unsigned long i;
 139        struct proc_dir_entry *ent = NULL;
 140        char buf[256];
 141
 142        printk("proc_ppc64: Creating /proc/ppc64/pmc\n");
 143
 144        /*
 145         * Create the root, system, and cpu directories as follows:
 146         *   /proc/ppc64/pmc/system 
 147         *   /proc/ppc64/pmc/cpu0 
 148         */
 149        spin_lock(&proc_ppc64_lock);
 150        if (proc_ppc64_root == NULL) {
 151                proc_ppc64_root = proc_mkdir("ppc64", 0);
 152                if (!proc_ppc64_root) {
 153                        spin_unlock(&proc_ppc64_lock);
 154                        return;
 155                }
 156        }
 157        spin_unlock(&proc_ppc64_lock);
 158
 159        ent = create_proc_entry("naca", S_IFREG|S_IRUGO, proc_ppc64_root);
 160        if ( ent ) {
 161                ent->nlink = 1;
 162                ent->data = naca;
 163                ent->size = 4096;
 164                ent->proc_fops = &nacamap_fops;
 165        }
 166        
 167        ent = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64_root);
 168        if ( ent ) {
 169                ent->nlink = 1;
 170                ent->data = systemcfg;
 171                ent->size = 4096;
 172                ent->proc_fops = &nacamap_fops;
 173        }
 174
 175        /* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
 176        ent = proc_mkdir("paca", proc_ppc64_root);
 177        if (ent) {
 178                for (i = 0; i < systemcfg->processorCount; i++)
 179                        proc_ppc64_create_paca(i, ent);
 180        }
 181
 182        /* Placeholder for rtas interfaces. */
 183        if (rtas_proc_dir == NULL) {
 184                rtas_proc_dir = proc_mkdir("rtas", proc_ppc64_root);
 185        }
 186
 187        proc_ppc64_create_smt();
 188
 189        /* Create the /proc/ppc64/pcifr for the Pci Flight Recorder.     */
 190        proc_pciFr_init(proc_ppc64_root);
 191
 192        proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root);
 193
 194        proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
 195        for (i = 0; i < systemcfg->processorCount; i++) {
 196                sprintf(buf, "cpu%ld", i); 
 197                proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root);
 198        }
 199
 200
 201        /* Create directories for the software counters. */
 202        for (i = 0; i < systemcfg->processorCount; i++) {
 203                ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
 204                                        proc_ppc64_pmc_cpu_root[i]);
 205                if (ent) {
 206                        ent->nlink = 1;
 207                        ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
 208                        ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
 209                        ent->write_proc = NULL;
 210                }
 211
 212                ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
 213                                        proc_ppc64_pmc_cpu_root[i]);
 214                if (ent) {
 215                        ent->nlink = 1;
 216                        ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
 217                        ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
 218                        ent->write_proc = NULL;
 219                }
 220        }
 221
 222        ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
 223                                proc_ppc64_pmc_system_root);
 224        if (ent) {
 225                ent->nlink = 1;
 226                ent->data = (void *)proc_ppc64_pmc_system_root;
 227                ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
 228                ent->write_proc = NULL;
 229        }
 230
 231        ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, 
 232                                proc_ppc64_pmc_system_root);
 233        if (ent) {
 234                ent->nlink = 1;
 235                ent->data = (void *)proc_ppc64_pmc_system_root;
 236                ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
 237                ent->write_proc = NULL;
 238        }
 239
 240        ent = create_proc_entry("profile", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
 241        if (ent) {
 242                ent->nlink = 1;
 243                ent->proc_fops = &proc_profile_operations;
 244                /* ent->size = (1+prof_len) * sizeof(unsigned int); */
 245        }
 246
 247        ent = create_proc_entry("trace", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
 248        if (ent) {
 249                ent->nlink = 1;
 250                ent->proc_fops = &proc_trace_operations;
 251                /* ent->size = (1+prof_len) * sizeof(unsigned int); */
 252        }
 253
 254        ent = create_proc_entry("timeslice", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
 255        if (ent) {
 256                ent->nlink = 1;
 257                ent->proc_fops = &proc_timeslice_operations;
 258        }
 259
 260        /* Create directories for the hardware counters. */
 261        for (i = 0; i < systemcfg->processorCount; i++) {
 262                ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
 263                                        proc_ppc64_pmc_cpu_root[i]);
 264                if (ent) {
 265                        ent->nlink = 1;
 266                        ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
 267                        ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
 268                        ent->write_proc = NULL;
 269                }
 270        }
 271
 272        ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
 273                                proc_ppc64_pmc_system_root);
 274        if (ent) {
 275                ent->nlink = 1;
 276                ent->data = (void *)proc_ppc64_pmc_system_root;
 277                ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
 278                ent->write_proc = NULL;
 279        }
 280}
 281
 282/* Read a page of raw data.  "data" points to the start addr.
 283 * Intended as a proc read function.
 284 */
 285static int proc_ppc64_page_read(char *page, char **start, off_t off,
 286                                int count, int *eof, void *data)
 287{
 288        int len = PAGE_SIZE - off;
 289        char *p = (char *)data;
 290
 291        if (len > count)
 292                len = count;
 293        if (len <= 0)
 294                return 0;
 295        /* Rely on a "hack" in fs/proc/generic.c.
 296         * If we could return a ptr to our own data this would be
 297         * trivial (currently *start must be either an offset, or
 298         * point into the given page).
 299         */
 300        memcpy(page, p+off, len);
 301        *start = (char *)len;
 302        return len;
 303}
 304
 305/* NOTE: since paca data is always in flux the values will never be a consistant set.
 306 * In theory it could be made consistent if we made the corresponding cpu
 307 * copy the page for us (via an IPI).  Probably not worth it.
 308 *
 309 */
 310static void proc_ppc64_create_paca(int num, struct proc_dir_entry *paca_dir)
 311{
 312        struct proc_dir_entry *ent;
 313        struct paca_struct *lpaca = paca + num;
 314        char buf[16];
 315
 316        sprintf(buf, "%02x", num);
 317        ent = create_proc_read_entry(buf, S_IRUSR, paca_dir, proc_ppc64_page_read, lpaca);
 318}
 319
 320/*
 321 * Find the requested 'file' given a proc token.
 322 *
 323 * Inputs: void * data: proc token
 324 * Output: int        : (0, ..., +N) = CPU number.
 325 *                      -1           = System.
 326 */
 327int proc_ppc64_pmc_find_file(void *data)
 328{
 329        int i;
 330
 331        if ((unsigned long)data == 
 332           (unsigned long) proc_ppc64_pmc_system_root) {
 333                return(-1); 
 334        } else {
 335                for (i = 0; i < systemcfg->processorCount; i++) {
 336                        if ((unsigned long)data ==
 337                           (unsigned long)proc_ppc64_pmc_cpu_root[i]) {
 338                                return(i); 
 339                        }
 340                }
 341        }
 342
 343        /* On error, just default to a type of system. */
 344        printk("proc_ppc64_pmc_find_file: failed to find file token.\n"); 
 345        return(-1); 
 346}
 347
 348int 
 349proc_ppc64_pmc_read(char *page, char **start, off_t off, 
 350                    int count, int *eof, char *buffer)
 351{
 352        int buffer_size, n;
 353
 354        if (count < 0) return 0;
 355
 356        if (buffer == NULL) {
 357                *eof = 1;
 358                return 0;
 359        }
 360
 361        /* Check for read beyond EOF */
 362        buffer_size = n = strlen(buffer);
 363        if (off >= buffer_size) {
 364                *eof = 1;
 365                return 0;
 366        }
 367        if (n > (buffer_size - off)) n = buffer_size - off;
 368
 369        /* Never return more than was requested */
 370        if (n > count) {
 371                n = count;
 372        } else {
 373                *eof = 1;
 374        }
 375
 376        memcpy(page, buffer + off, n);
 377
 378        *start = page;
 379
 380        return n;
 381}
 382
 383int 
 384proc_ppc64_pmc_stab_read(char *page, char **start, off_t off, 
 385                         int count, int *eof, void *data)
 386{
 387        int n, file;
 388        char *buffer = NULL;
 389
 390        if (count < 0) return 0;
 391        spin_lock(&proc_ppc64_lock);
 392
 393        /* Figure out which file is being request. */
 394        file = proc_ppc64_pmc_find_file(data);
 395
 396        /* Update the counters and the text buffer representation. */
 397        buffer = ppc64_pmc_stab(file);
 398
 399        /* Put the data into the requestor's buffer. */
 400        n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer); 
 401
 402        spin_unlock(&proc_ppc64_lock);
 403        return n;
 404}
 405
 406int 
 407proc_ppc64_pmc_htab_read(char *page, char **start, off_t off, 
 408                         int count, int *eof, void *data)
 409{
 410        int n, file;
 411        char *buffer = NULL;
 412
 413        if (count < 0) return 0;
 414        spin_lock(&proc_ppc64_lock);
 415
 416        /* Figure out which file is being request. */
 417        file = proc_ppc64_pmc_find_file(data);
 418
 419        /* Update the counters and the text buffer representation. */
 420        buffer = ppc64_pmc_htab(file);
 421
 422        /* Put the data into the requestor's buffer. */
 423        n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
 424
 425        spin_unlock(&proc_ppc64_lock);
 426        return n;
 427}
 428
 429static ssize_t read_profile(struct file *file, char *buf,
 430                            size_t count, loff_t *ppos)
 431{
 432        unsigned long p = *ppos;
 433        ssize_t read;
 434        char * pnt;
 435        unsigned int sample_step = 4;
 436
 437        if (p >= (perfmon_base.profile_length+1)) return 0;
 438        if (count > (perfmon_base.profile_length+1) - p)
 439                count = (perfmon_base.profile_length+1) - p;
 440        read = 0;
 441
 442        while (p < sizeof(unsigned int) && count > 0) {
 443                put_user(*((char *)(&sample_step)+p),buf);
 444                buf++; p++; count--; read++;
 445        }
 446        pnt = (char *)(perfmon_base.profile_buffer) + p - sizeof(unsigned int);
 447        copy_to_user(buf,(void *)pnt,count);
 448        p += count;
 449        read += count;
 450        *ppos = p;
 451        return read;
 452}
 453
 454static ssize_t write_profile(struct file * file, const char * buf,
 455                             size_t count, loff_t *ppos)
 456{
 457        return(0);
 458}
 459
 460static ssize_t read_trace(struct file *file, char *buf,
 461                            size_t count, loff_t *ppos)
 462{
 463        unsigned long p = *ppos;
 464        char * pnt;
 465
 466        if (p >= (perfmon_base.trace_length)) return 0;
 467        if (count > (perfmon_base.trace_length) - p)
 468                count = (perfmon_base.trace_length) - p;
 469
 470        pnt = (char *)(perfmon_base.trace_buffer) + p;
 471        copy_to_user(buf,(void *)pnt,count);
 472        p += count;
 473        *ppos = p;
 474        return count;
 475}
 476
 477static ssize_t write_trace(struct file * file, const char * buf,
 478                             size_t count, loff_t *ppos)
 479{
 480        return(0);
 481}
 482
 483static ssize_t read_timeslice(struct file *file, char *buf,
 484                              size_t count, loff_t *ppos)
 485{
 486        unsigned long p = *ppos;
 487        ssize_t read;
 488        char * pnt;
 489
 490        if (p >= (perfmon_base.timeslice_length)) return 0;
 491        if (count > (perfmon_base.timeslice_length) - p)
 492                count = (perfmon_base.timeslice_length) - p;
 493
 494        pnt = (char *)(perfmon_base.timeslice_buffer) + p;
 495        copy_to_user(buf,(void *)pnt,count);
 496        *ppos = p + count;
 497        return count;
 498}
 499
 500static ssize_t write_timeslice(struct file * file, const char * buf,
 501                               size_t count, loff_t *ppos)
 502{
 503        return(0);
 504}
 505
 506int 
 507proc_ppc64_pmc_hw_read(char *page, char **start, off_t off, 
 508                             int count, int *eof, void *data)
 509{
 510        int n, file;
 511        char *buffer = NULL;
 512
 513        if (count < 0) return 0;
 514        spin_lock(&proc_ppc64_lock);
 515
 516        /* Figure out which file is being request. */
 517        file = proc_ppc64_pmc_find_file(data);
 518
 519        /* Update the counters and the text buffer representation. */
 520        buffer = ppc64_pmc_hw(file);
 521
 522        /* Put the data into the requestor's buffer. */
 523        n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
 524
 525        spin_unlock(&proc_ppc64_lock);
 526        return n;
 527}
 528
 529/* 
 530 * DRENG the remainder of these functions still need work ...
 531 */
 532void pmc_proc_init(struct proc_dir_entry *iSeries_proc)
 533{
 534    struct proc_dir_entry *ent = NULL;
 535
 536    ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc);
 537    if (!ent) return;
 538    ent->nlink = 1;
 539    ent->data = (void *)0;
 540    ent->read_proc = proc_get_lpevents;
 541    ent->write_proc = proc_reset_lpevents;
 542
 543    ent = create_proc_entry("titanTod", S_IFREG|S_IRUGO, iSeries_proc);
 544    if (!ent) return;
 545    ent->nlink = 1;
 546    ent->data = (void *)0;
 547    ent->size = 0;
 548    ent->read_proc = proc_get_titanTod;
 549    ent->write_proc = NULL;
 550
 551    pmc_proc_root = proc_mkdir("pmc", iSeries_proc);
 552    if (!pmc_proc_root) return;
 553
 554    ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
 555    if (!ent) return;
 556    ent->nlink = 1;
 557    ent->data = (void *)0;
 558    ent->read_proc = proc_pmc_get_control;
 559    ent->write_proc = proc_pmc_set_control;
 560
 561}
 562
 563static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len)
 564{
 565        if ( len <= off+count)
 566                *eof = 1;
 567        *start = page+off;
 568        len -= off;
 569        if ( len > count )
 570                len = count;
 571        if ( len < 0 )
 572                len = 0;
 573        return len;
 574}
 575
 576static char * lpEventTypes[9] = {
 577        "Hypervisor\t\t",
 578        "Machine Facilities\t",
 579        "Session Manager\t",
 580        "SPD I/O\t\t",
 581        "Virtual Bus\t\t",
 582        "PCI I/O\t\t",
 583        "RIO I/O\t\t",
 584        "Virtual Lan\t\t",
 585        "Virtual I/O\t\t"
 586        };
 587        
 588
 589int proc_get_lpevents
 590(char *page, char **start, off_t off, int count, int *eof, void *data)
 591{
 592        unsigned i;
 593        int len = 0;
 594
 595        len += sprintf( page+len, "LpEventQueue 0\n" );
 596        len += sprintf( page+len, "  events processed:\t%lu\n",
 597                        (unsigned long)xItLpQueue.xLpIntCount );
 598        for (i=0; i<9; ++i) {
 599                len += sprintf( page+len, "    %s %10lu\n",
 600                        lpEventTypes[i],
 601                        (unsigned long)xItLpQueue.xLpIntCountByType[i] );
 602        }
 603        len += sprintf( page+len, "\n  events processed by processor:\n" );
 604        for (i=0; i<systemcfg->processorCount; ++i) {
 605                len += sprintf( page+len, "    CPU%02d  %10u\n",
 606                        i, paca[i].lpEvent_count );
 607        }
 608
 609        return pmc_calc_metrics( page, start, off, count, eof, len );
 610
 611}
 612
 613int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data )
 614{
 615        return count;
 616}
 617
 618static unsigned long startTitan = 0;
 619static unsigned long startTb = 0;
 620
 621
 622int proc_get_titanTod
 623(char *page, char **start, off_t off, int count, int *eof, void *data)
 624{
 625        int len = 0;
 626        unsigned long tb0, titan_tod;
 627
 628        tb0 = get_tb();
 629        titan_tod = HvCallXm_loadTod();
 630
 631        len += sprintf( page+len, "Titan\n" );
 632        len += sprintf( page+len, "  time base =          %016lx\n", tb0 );
 633        len += sprintf( page+len, "  titan tod =          %016lx\n", titan_tod );
 634        len += sprintf( page+len, "  xProcFreq =          %016x\n", xIoHriProcessorVpd[0].xProcFreq );
 635        len += sprintf( page+len, "  xTimeBaseFreq =      %016x\n", xIoHriProcessorVpd[0].xTimeBaseFreq );
 636        len += sprintf( page+len, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy );
 637        len += sprintf( page+len, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec );
 638
 639        if ( !startTitan ) {
 640                startTitan = titan_tod;
 641                startTb = tb0;
 642        }
 643        else {
 644                unsigned long titan_usec = (titan_tod - startTitan) >> 12;
 645                unsigned long tb_ticks = (tb0 - startTb);
 646                unsigned long titan_jiffies = titan_usec / (1000000/HZ);
 647                unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
 648                unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec;
 649                unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
 650                unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
 651                unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
 652                unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec;
 653                unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec;
 654                
 655                len += sprintf( page+len, "  titan elapsed = %lu uSec\n", titan_usec);
 656                len += sprintf( page+len, "  tb elapsed    = %lu ticks\n", tb_ticks);
 657                len += sprintf( page+len, "  titan jiffies = %lu.%04lu \n", titan_jiffies, titan_jiff_rem_usec );                               
 658                len += sprintf( page+len, "  tb jiffies    = %lu.%04lu\n", tb_jiffies, tb_jiff_rem_usec );
 659                len += sprintf( page+len, "  new tb_ticks_per_jiffy = %lu\n", new_tb_ticks_per_jiffy ); 
 660
 661        }
 662        
 663        return pmc_calc_metrics( page, start, off, count, eof, len );
 664}
 665        
 666int proc_pmc_get_control
 667(char *page, char **start, off_t off, int count, int *eof, void *data)
 668{
 669        int len = 0;
 670
 671        if ( proc_pmc_control_mode == PMC_CONTROL_CPI ) {
 672                unsigned long mach_cycles   = mfspr( PMC5 );
 673                unsigned long inst_complete = mfspr( PMC4 );
 674                unsigned long inst_dispatch = mfspr( PMC3 );
 675                unsigned long thread_active_run = mfspr( PMC1 );
 676                unsigned long thread_active  = mfspr( PMC2 );
 677                unsigned long cpi = 0;
 678                unsigned long cpithou = 0;
 679                unsigned long remain;
 680        
 681                if ( inst_complete ) {
 682                        cpi = thread_active_run / inst_complete;
 683                        remain = thread_active_run % inst_complete;
 684                        if ( inst_complete > 1000000 ) 
 685                                cpithou = remain / ( inst_complete / 1000 );
 686                        else 
 687                                cpithou = ( remain * 1000 ) / inst_complete;
 688                }
 689                len += sprintf( page+len, "PMC CPI Mode\nRaw Counts\n" );
 690                len += sprintf( page+len, "machine cycles           : %12lu\n", mach_cycles );
 691                len += sprintf( page+len, "thread active cycles     : %12lu\n\n", thread_active );
 692
 693                len += sprintf( page+len, "instructions completed   : %12lu\n", inst_complete );
 694                len += sprintf( page+len, "instructions dispatched  : %12lu\n", inst_dispatch );
 695                len += sprintf( page+len, "thread active run cycles : %12lu\n", thread_active_run );
 696
 697                len += sprintf( page+len, "thread active run cycles/instructions completed\n" );
 698                len += sprintf( page+len, "CPI = %lu.%03lu\n", cpi, cpithou );
 699                
 700        }
 701        else if ( proc_pmc_control_mode == PMC_CONTROL_TLB ) {
 702                len += sprintf( page+len, "PMC TLB Mode\n" );
 703                len += sprintf( page+len, "I-miss count             : %12lu\n", mfspr( PMC1 ) );
 704                len += sprintf( page+len, "I-miss latency           : %12lu\n", mfspr( PMC2 ) );
 705                len += sprintf( page+len, "D-miss count             : %12lu\n", mfspr( PMC3 ) );
 706                len += sprintf( page+len, "D-miss latency           : %12lu\n", mfspr( PMC4 ) );
 707                len += sprintf( page+len, "IERAT miss count         : %12lu\n", mfspr( PMC5 ) );
 708                len += sprintf( page+len, "D-reference count        : %12lu\n", mfspr( PMC6 ) );
 709                len += sprintf( page+len, "miss PTEs searched       : %12lu\n", mfspr( PMC7 ) );
 710                len += sprintf( page+len, "miss >8 PTEs searched    : %12lu\n", mfspr( PMC8 ) );
 711        }
 712        /* IMPLEMENT ME */
 713        return pmc_calc_metrics( page, start, off, count, eof, len );
 714}
 715
 716unsigned long proc_pmc_conv_int( const char *buf, unsigned count )
 717{
 718        const char * p;
 719        char b0, b1;
 720        unsigned v, multiplier, mult, i;
 721        unsigned long val;
 722        multiplier = 10;
 723        p = buf;
 724        if ( count >= 3 ) {
 725                b0 = buf[0];
 726                b1 = buf[1];
 727                if ( ( b0 == '0' ) &&
 728                     ( ( b1 == 'x' ) || ( b1 == 'X' ) ) ) {
 729                        p = buf + 2;
 730                        count -= 2;
 731                        multiplier = 16;
 732                }
 733                        
 734        }
 735        val = 0;
 736        for ( i=0; i<count; ++i ) {
 737                b0 = *p++;
 738                v = 0;
 739                mult = multiplier;
 740                if ( ( b0 >= '0' ) && ( b0 <= '9' ) ) 
 741                        v = b0 - '0';
 742                else if ( multiplier == 16 ) {
 743                        if ( ( b0 >= 'a' ) && ( b0 <= 'f' ) )
 744                                v = b0 - 'a' + 10;
 745                        else if ( ( b0 >= 'A' ) && ( b0 <= 'F' ) )
 746                                v = b0 - 'A' + 10;
 747                        else 
 748                                mult = 1;
 749                }
 750                else
 751                        mult = 1;
 752                val *= mult;
 753                val += v;
 754        }
 755
 756        return val;
 757
 758}
 759
 760static inline void proc_pmc_stop(void)
 761{
 762        /* Freeze all counters, leave everything else alone */
 763        mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
 764}
 765
 766static inline void proc_pmc_start(void)
 767{
 768        /* Unfreeze all counters, leave everything else alone */
 769        mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 );
 770
 771}
 772
 773static inline void proc_pmc_reset(void)
 774{
 775        /* Clear all the PMCs to zeros 
 776         * Assume a "stop" has already frozen the counters
 777         * Clear all the PMCs
 778         */
 779        mtspr( PMC1, 0 );
 780        mtspr( PMC2, 0 );
 781        mtspr( PMC3, 0 );
 782        mtspr( PMC4, 0 );
 783        mtspr( PMC5, 0 );
 784        mtspr( PMC6, 0 );
 785        mtspr( PMC7, 0 );
 786        mtspr( PMC8, 0 );
 787
 788}
 789
 790static inline void proc_pmc_cpi(void)
 791{
 792        /* Configure the PMC registers to count cycles and instructions */
 793        /* so we can compute cpi */
 794        /*
 795         * MMCRA[30]    = 1     Don't count in wait state (CTRL[31]=0)
 796         * MMCR0[6]     = 1     Freeze counters when any overflow
 797         * MMCR0[19:25] = 0x01  PMC1 counts Thread Active Run Cycles
 798         * MMCR0[26:31] = 0x05  PMC2 counts Thread Active Cycles
 799         * MMCR1[0:4]   = 0x07  PMC3 counts Instructions Dispatched
 800         * MMCR1[5:9]   = 0x03  PMC4 counts Instructions Completed
 801         * MMCR1[10:14] = 0x06  PMC5 counts Machine Cycles
 802         *
 803         */
 804
 805        proc_pmc_control_mode = PMC_CONTROL_CPI;
 806        
 807        /* Indicate to hypervisor that we are using the PMCs */
 808        get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
 809
 810        /* Freeze all counters */
 811        mtspr( MMCR0, 0x80000000 );
 812        mtspr( MMCR1, 0x00000000 );
 813        
 814        /* Clear all the PMCs */
 815        mtspr( PMC1, 0 );
 816        mtspr( PMC2, 0 );
 817        mtspr( PMC3, 0 );
 818        mtspr( PMC4, 0 );
 819        mtspr( PMC5, 0 );
 820        mtspr( PMC6, 0 );
 821        mtspr( PMC7, 0 );
 822        mtspr( PMC8, 0 );
 823
 824        /* Freeze counters in Wait State (CTRL[31]=0) */
 825        mtspr( MMCRA, 0x00000002 );
 826
 827        /* PMC3<-0x07, PMC4<-0x03, PMC5<-0x06 */
 828        mtspr( MMCR1, 0x38cc0000 );
 829
 830        mb();
 831        
 832        /* PMC1<-0x01, PMC2<-0x05
 833         * Start all counters
 834         */
 835        mtspr( MMCR0, 0x02000045 );
 836        
 837}
 838
 839static inline void proc_pmc_tlb(void)
 840{
 841        /* Configure the PMC registers to count tlb misses  */
 842        /*
 843         * MMCR0[6]     = 1     Freeze counters when any overflow
 844         * MMCR0[19:25] = 0x55  Group count
 845         *   PMC1 counts  I misses
 846         *   PMC2 counts  I miss duration (latency)
 847         *   PMC3 counts  D misses
 848         *   PMC4 counts  D miss duration (latency)
 849         *   PMC5 counts  IERAT misses
 850         *   PMC6 counts  D references (including PMC7)
 851         *   PMC7 counts  miss PTEs searched
 852         *   PMC8 counts  miss >8 PTEs searched
 853         *   
 854         */
 855
 856        proc_pmc_control_mode = PMC_CONTROL_TLB;
 857        
 858        /* Indicate to hypervisor that we are using the PMCs */
 859        get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
 860
 861        /* Freeze all counters */
 862        mtspr( MMCR0, 0x80000000 );
 863        mtspr( MMCR1, 0x00000000 );
 864        
 865        /* Clear all the PMCs */
 866        mtspr( PMC1, 0 );
 867        mtspr( PMC2, 0 );
 868        mtspr( PMC3, 0 );
 869        mtspr( PMC4, 0 );
 870        mtspr( PMC5, 0 );
 871        mtspr( PMC6, 0 );
 872        mtspr( PMC7, 0 );
 873        mtspr( PMC8, 0 );
 874
 875        mtspr( MMCRA, 0x00000000 );
 876
 877        mb();
 878        
 879        /* PMC1<-0x55
 880         * Start all counters
 881         */
 882        mtspr( MMCR0, 0x02001540 );
 883        
 884}
 885
 886int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data )
 887{
 888        char stkbuf[10];
 889
 890        if (count > 9)
 891                count = 9;
 892        if (copy_from_user (stkbuf, buffer, count))
 893                return -EFAULT;
 894
 895        stkbuf[count] = 0;
 896
 897        if      ( ! strncmp( stkbuf, "stop", 4 ) )
 898                proc_pmc_stop();
 899        else if ( ! strncmp( stkbuf, "start", 5 ) )
 900                proc_pmc_start();
 901        else if ( ! strncmp( stkbuf, "reset", 5 ) )
 902                proc_pmc_reset();
 903        else if ( ! strncmp( stkbuf, "cpi", 3 ) )
 904                proc_pmc_cpi();
 905        else if ( ! strncmp( stkbuf, "tlb", 3 ) )
 906                proc_pmc_tlb();
 907        
 908        /* IMPLEMENT ME */
 909        return count;
 910}
 911
 912int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data )
 913{
 914        unsigned long v;
 915        v = proc_pmc_conv_int( buffer, count );
 916        v = v & ~0x04000000;    /* Don't allow interrupts for now */
 917        if ( v & ~0x80000000 )  /* Inform hypervisor we are using PMCs */
 918                get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
 919        else
 920                get_paca()->xLpPacaPtr->xPMCRegsInUse = 0;
 921        mtspr( MMCR0, v );
 922        
 923        return count;   
 924}
 925
 926int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data )
 927{
 928        unsigned long v;
 929        v = proc_pmc_conv_int( buffer, count );
 930        mtspr( MMCR1, v );
 931
 932        return count;
 933}
 934
 935int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data )
 936{
 937        unsigned long v;
 938        v = proc_pmc_conv_int( buffer, count );
 939        v = v & ~0x00008000;    /* Don't allow interrupts for now */
 940        mtspr( MMCRA, v );
 941
 942        return count;
 943}
 944
 945
 946int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data )
 947{
 948        unsigned long v;
 949        v = proc_pmc_conv_int( buffer, count );
 950        mtspr( PMC1, v );
 951
 952        return count;
 953}
 954
 955int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data )
 956{
 957        unsigned long v;
 958        v = proc_pmc_conv_int( buffer, count );
 959        mtspr( PMC2, v );
 960
 961        return count;
 962}
 963
 964int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data )
 965{
 966        unsigned long v;
 967        v = proc_pmc_conv_int( buffer, count );
 968        mtspr( PMC3, v );
 969
 970        return count;
 971}
 972
 973int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data )
 974{
 975        unsigned long v;
 976        v = proc_pmc_conv_int( buffer, count );
 977        mtspr( PMC4, v );
 978
 979        return count;
 980}
 981
 982int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data )
 983{
 984        unsigned long v;
 985        v = proc_pmc_conv_int( buffer, count );
 986        mtspr( PMC5, v );
 987
 988        return count;
 989}
 990
 991int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data )
 992{
 993        unsigned long v;
 994        v = proc_pmc_conv_int( buffer, count );
 995        mtspr( PMC6, v );
 996
 997        return count;
 998}
 999
1000int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data )
1001{
1002        unsigned long v;
1003        v = proc_pmc_conv_int( buffer, count );
1004        mtspr( PMC7, v );
1005
1006        return count;
1007}
1008
1009int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data )
1010{
1011        unsigned long v;
1012        v = proc_pmc_conv_int( buffer, count );
1013        mtspr( PMC8, v );
1014
1015        return count;
1016}
1017
1018static loff_t nacamap_seek( struct file *file, loff_t off, int whence)
1019{
1020        loff_t new;
1021        struct proc_dir_entry *dp;
1022
1023        dp = file->f_dentry->d_inode->u.generic_ip;
1024
1025        switch(whence) {
1026        case 0:
1027                new = off;
1028                break;
1029        case 1:
1030                new = file->f_pos + off;
1031                break;
1032        case 2:
1033                new = dp->size + off;
1034                break;
1035        default:
1036                return -EINVAL;
1037        }
1038        if ( new < 0 || new > dp->size )
1039                return -EINVAL;
1040        return (file->f_pos = new);
1041}
1042
1043static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos)
1044{
1045        unsigned pos = *ppos;
1046        struct proc_dir_entry *dp;
1047
1048        dp = file->f_dentry->d_inode->u.generic_ip;
1049
1050        if ( pos >= dp->size )
1051                return 0;
1052        if ( nbytes >= dp->size )
1053                nbytes = dp->size;
1054        if ( pos + nbytes > dp->size )
1055                nbytes = dp->size - pos;
1056
1057        copy_to_user( buf, (char *)dp->data + pos, nbytes );
1058        *ppos = pos + nbytes;
1059        return nbytes;
1060}
1061
1062static int nacamap_mmap( struct file *file, struct vm_area_struct *vma )
1063{
1064        struct proc_dir_entry *dp;
1065
1066        dp = file->f_dentry->d_inode->u.generic_ip;
1067
1068        vma->vm_flags |= VM_SHM | VM_LOCKED;
1069
1070        if ((vma->vm_end - vma->vm_start) > dp->size)
1071                return -EINVAL;
1072
1073        remap_page_range( vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
1074        return 0;
1075}
1076
1077static int proc_ppc64_smt_snooze_read(char *page, char **start, off_t off,
1078                                      int count, int *eof, void *data)
1079{
1080        if (naca->smt_snooze_delay)
1081                return sprintf(page, "%lu\n", naca->smt_snooze_delay);
1082        else
1083                return sprintf(page, "disabled\n");
1084}
1085
1086static int proc_ppc64_smt_snooze_write(struct file* file, const char *buffer,
1087                                       unsigned long count, void *data)
1088{
1089        unsigned long val;
1090        char val_string[22];
1091
1092        if (!capable(CAP_SYS_ADMIN))
1093                return -EACCES;
1094
1095        if (count > sizeof(val_string) - 1)
1096                return -EINVAL;
1097
1098        if (copy_from_user(val_string, buffer, count))
1099                return -EFAULT;
1100
1101        val_string[count] = '\0';
1102
1103        if (val_string[0] == '0' && (val_string[1] == '\n' || val_string[1] == '\0')) {
1104                naca->smt_snooze_delay = 0;
1105                return count;
1106        }
1107
1108        val = simple_strtoul(val_string, NULL, 10);
1109        if (val != 0)
1110                naca->smt_snooze_delay = val;
1111        else
1112                return -EINVAL;
1113
1114        return count;
1115}
1116
1117static int proc_ppc64_smt_state_read(char *page, char **start, off_t off,
1118                                      int count, int *eof, void *data)
1119{
1120        switch(naca->smt_state) {
1121        case SMT_OFF:
1122                return sprintf(page, "off\n");
1123                break;
1124        case SMT_ON:
1125                return sprintf(page, "on\n");
1126                break;
1127        case SMT_DYNAMIC:
1128                return sprintf(page, "dynamic\n");
1129                break;
1130        default:
1131                return sprintf(page, "unknown\n");
1132                break;
1133        }
1134}
1135
1136void proc_ppc64_create_smt(void)
1137{
1138        struct proc_dir_entry *ent_snooze =
1139                create_proc_entry("smt-snooze-delay", S_IRUGO | S_IWUSR,
1140                                  proc_ppc64_root);
1141        struct proc_dir_entry *ent_enabled =
1142                create_proc_entry("smt-enabled", S_IRUGO | S_IWUSR,
1143                                  proc_ppc64_root);
1144        if (ent_snooze) {
1145                ent_snooze->nlink = 1;
1146                ent_snooze->data = NULL;
1147                ent_snooze->read_proc = (void *)proc_ppc64_smt_snooze_read;
1148                ent_snooze->write_proc = (void *)proc_ppc64_smt_snooze_write;
1149        }
1150
1151        if (ent_enabled) {
1152                ent_enabled->nlink = 1;
1153                ent_enabled->data = NULL;
1154                ent_enabled->read_proc = (void *)proc_ppc64_smt_state_read;
1155                ent_enabled->write_proc = NULL;
1156        }
1157}
1158
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.