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