1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
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
146
147
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
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
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
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
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
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
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
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
283
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
296
297
298
299
300 memcpy(page, p+off, len);
301 *start = (char *)len;
302 return len;
303}
304
305
306
307
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
322
323
324
325
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
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
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
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
394 file = proc_ppc64_pmc_find_file(data);
395
396
397 buffer = ppc64_pmc_stab(file);
398
399
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
417 file = proc_ppc64_pmc_find_file(data);
418
419
420 buffer = ppc64_pmc_htab(file);
421
422
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
517 file = proc_ppc64_pmc_find_file(data);
518
519
520 buffer = ppc64_pmc_hw(file);
521
522
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
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
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
763 mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
764}
765
766static inline void proc_pmc_start(void)
767{
768
769 mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 );
770
771}
772
773static inline void proc_pmc_reset(void)
774{
775
776
777
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
793
794
795
796
797
798
799
800
801
802
803
804
805 proc_pmc_control_mode = PMC_CONTROL_CPI;
806
807
808 get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
809
810
811 mtspr( MMCR0, 0x80000000 );
812 mtspr( MMCR1, 0x00000000 );
813
814
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
825 mtspr( MMCRA, 0x00000002 );
826
827
828 mtspr( MMCR1, 0x38cc0000 );
829
830 mb();
831
832
833
834
835 mtspr( MMCR0, 0x02000045 );
836
837}
838
839static inline void proc_pmc_tlb(void)
840{
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 proc_pmc_control_mode = PMC_CONTROL_TLB;
857
858
859 get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
860
861
862 mtspr( MMCR0, 0x80000000 );
863 mtspr( MMCR1, 0x00000000 );
864
865
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
880
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
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;
917 if ( v & ~0x80000000 )
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;
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