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