1 /*
2  * Code to configure and utilize the ppc64 pmc hardware.  Generally, the
3  * following functions are supported:
4  *    1. Kernel profile based on decrementer ticks
5  *    2. Kernel profile based on PMC execution cycles
6  *    3. Trace based on arbitrary PMC counter
7  *    4. Timeslice data capture of arbitrary collections of PMCs
8  *
9  * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
10  */
11 
12 #include <asm/proc_fs.h>
13 #include <asm/paca.h>
14 #include <asm/iSeries/ItLpPaca.h>
15 #include <asm/iSeries/ItLpQueue.h>
16 #include <asm/processor.h>
17 #include <linux/proc_fs.h>
18 #include <linux/spinlock.h>
19 #include <asm/pmc.h>
20 #include <asm/uaccess.h>
21 #include <asm/naca.h>
22 #include <asm/perfmon.h>
23 #include <asm/iSeries/HvCall.h>
24 #include <asm/hvcall.h>
25 #include <asm/cputable.h>
26 
27 extern char _stext[], _etext[], _end[];
28 struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, 0, 0, PMC_STATE_INITIAL};
29 
30 int alloc_perf_buffer(int size);
31 int free_perf_buffer(void);
32 int clear_buffers(void);
33 void pmc_stop(void *data);
34 void pmc_clear(void *data);
35 void pmc_start(void *data);
36 void pmc_touch_bolted(void *data);
37 void dump_pmc_struct(struct perfmon_struct *perfdata);
38 void dump_hardware_pmc_struct(void *perfdata);
39 int  decr_profile(void *data);
40 int  pmc_profile(struct perfmon_struct *perfdata);
41 int  pmc_set_general(struct perfmon_struct *perfdata);
42 int  pmc_set_user_general(struct perfmon_struct *perfdata);
43 void pmc_configure(void *data);
44 int pmc_timeslice_enable(struct perfmon_struct *perfdata);
45 int pmc_timeslice_disable(struct perfmon_struct *perfdata);
46 int pmc_timeslice_set(struct perfmon_struct *perfdata);
47 void pmc_dump_timeslice(struct perfmon_struct *perfdata);
48 void pmc_trace_rec_type(unsigned long type);
49 void pmc_timeslice_data_collect(void *data);
50 int pmc_timeslice_tick(void);
51 int perfmon_buffer_ctl(void *data);
52 int perfmon_dump_ctl(void *data);
53 int perfmon_profile_ctl(void *data);
54 int perfmon_trace_ctl(void *data);
55 int perfmon_timeslice_ctl(void *data);
56 
57 #define PMC_MAX_CPUS     48
58 #define PMC_MAX_COUNTERS 8
59 #define PMC_SLICES_STAR  64
60 #define PMC_SLICES_GP    28
61 #define PMC_SLICES_MAX   64
62 #define PMC_TICK_FACTOR  10
63 
64 int pmc_timeslice_enabled = 0, pmc_timeslice_top = 0;
65 int pmc_tick_count[PMC_MAX_CPUS], pmc_timeslice[PMC_MAX_CPUS];
66 
67 unsigned long pmc_timeslice_data[PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS];
68 
69 /*
70  * DRENG: todo:
71  * add api to add config entries (entry, values), and bump pmc_timeslice_top
72  *   value
73  * add api to get data from kernel (entry, values)
74  */
75 unsigned long pmc_timeslice_config[PMC_SLICES_MAX * 5];
76 
77 static spinlock_t pmc_lock = SPIN_LOCK_UNLOCKED;
78 asmlinkage int
sys_perfmonctl(int cmd,void * data)79 sys_perfmonctl (int cmd, void *data)
80 {
81 	struct perfmon_struct *pdata;
82 	int err;
83 
84 	printk("sys_perfmonctl: cmd = 0x%x\n", cmd);
85 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
86 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
87 	switch(cmd) {
88 	case PMC_CMD_BUFFER:
89 		perfmon_buffer_ctl(data);
90 		break;
91 	case PMC_CMD_DUMP:
92 		perfmon_dump_ctl(data);
93 		break;
94 	case PMC_CMD_DECR_PROFILE: /* NIA time sampling */
95 		decr_profile(data);
96 		break;
97 	case PMC_CMD_PROFILE:
98 		perfmon_profile_ctl(pdata);
99 		break;
100 	case PMC_CMD_TRACE:
101 		perfmon_trace_ctl(pdata);
102 		break;
103 	case PMC_CMD_TIMESLICE:
104 		perfmon_timeslice_ctl(pdata);
105 		break;
106 #if 0
107 	case PMC_OP_TIMESLICE:
108 		pmc_enable_timeslice(pdata);
109 		break;
110 	case PMC_OP_DUMP_TIMESLICE:
111 		pmc_dump_timeslice(pdata);
112 		smp_call_function(pmc_dump_timeslice, (void *)pdata, 0, 1);
113 		break;
114 #endif
115 	default:
116 		printk("Perfmon: Unknown command\n");
117 		break;
118 	}
119 
120 	kfree(pdata);
121 	return 0;
122 }
123 
perfmon_buffer_ctl(void * data)124 int perfmon_buffer_ctl(void *data) {
125 	struct perfmon_struct *pdata;
126 	int err;
127 
128 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
129 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
130 
131 	switch(pdata->header.subcmd) {
132 	case PMC_SUBCMD_BUFFER_ALLOC:
133 		alloc_perf_buffer(0);
134 		break;
135 	case PMC_SUBCMD_BUFFER_FREE:
136 		free_perf_buffer();
137 		break;
138 	case PMC_SUBCMD_BUFFER_CLEAR:
139 		clear_buffers();
140 		break;
141 	default:
142 		return(-1);
143 	}
144 
145 	return(0);
146 }
147 
alloc_perf_buffer(int size)148 int alloc_perf_buffer(int size)
149 {
150 	int i;
151 
152 	printk("Perfmon: allocate buffer\n");
153 	if(perfmon_base.state == PMC_STATE_INITIAL) {
154 		perfmon_base.profile_length = (((unsigned long) &_etext -
155 				   (unsigned long) &_stext) >> 2) * sizeof(int);
156 		perfmon_base.profile_buffer = (unsigned long)btmalloc(perfmon_base.profile_length);
157 		perfmon_base.trace_length = 1024*1024*16;
158 		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
159 
160 		perfmon_base.timeslice_length = PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS;
161 		perfmon_base.timeslice_buffer = (unsigned long)pmc_timeslice_data;
162 
163 		if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {
164 			memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
165 			printk("Profile buffer created at address 0x%lx of length 0x%lx\n",
166 			       perfmon_base.profile_buffer, perfmon_base.profile_length);
167 		} else {
168 			printk("Profile buffer creation failed\n");
169 			return 0;
170 		}
171 
172 		/* Fault in the first bolted segment - it then remains in the stab for all time */
173 		pmc_touch_bolted(NULL);
174 		smp_call_function(pmc_touch_bolted, (void *)NULL, 0, 1);
175 
176 		for (i=0; i<MAX_PACAS; ++i) {
177 			paca[i].prof_shift = 2;
178 			paca[i].prof_len = perfmon_base.profile_length;
179 			paca[i].prof_buffer = (unsigned *)(perfmon_base.profile_buffer);
180 			paca[i].prof_stext = (unsigned *)&_stext;
181 
182 			paca[i].prof_etext = (unsigned *)&_etext;
183 			mb();
184 		}
185 
186 		perfmon_base.state = PMC_STATE_READY;
187 	}
188 
189 	return 0;
190 }
191 
free_perf_buffer()192 int free_perf_buffer()
193 {
194 	printk("Perfmon: free buffer\n");
195 
196 	if(perfmon_base.state == PMC_STATE_INITIAL) {
197 		printk("Perfmon: free buffer failed - no buffer was allocated.\n");
198 		return -1;
199 	}
200 
201 	btfree((void *)perfmon_base.profile_buffer);
202 	btfree((void *)perfmon_base.trace_buffer);
203 
204 	perfmon_base.profile_length = 0;
205 	perfmon_base.profile_buffer = 0;
206 	perfmon_base.trace_buffer   = 0;
207 	perfmon_base.trace_length   = 0;
208 	perfmon_base.trace_end      = 0;
209 	perfmon_base.state = PMC_STATE_INITIAL;
210 
211 	return(0);
212 }
213 
clear_buffers()214 int clear_buffers()
215 {
216 	int i, j;
217 
218 	if(perfmon_base.state == PMC_STATE_INITIAL) {
219 		printk("Perfmon: clear buffer failed - no buffer was allocated.\n");
220 		return -1;
221 	}
222 
223 	printk("Perfmon: clear buffer\n");
224 
225 	/* Stop counters on all [PMC_MAX_CPUS]processors -- blocking */
226 	pmc_stop(NULL);
227 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
228 
229 	/* Clear the buffers */
230 	memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
231 	memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);
232 	memset((char *)perfmon_base.timeslice_buffer, 0, perfmon_base.timeslice_length);
233 
234 	/* Reset the trace buffer point */
235 	perfmon_base.trace_end = 0;
236 
237 	for (i=0; i<MAX_PACAS; ++i) {
238 		for(j=0; j<8; j++) {
239 			paca[i].pmcc[j] = 0;
240 		}
241 	}
242 #if 0
243 	/* Reset the timeslice data */
244 	for(i=0; i<(PMC_MAX_CPUS*PMC_MAX_COUNTERS*PMC_SLICES_MAX); i++) {
245 		pmc_timeslice_data[i] = 0;
246 	}
247 #endif
248 	/* Restart counters on all processors -- blocking */
249 	pmc_start(NULL);
250 	smp_call_function(pmc_start, (void *)NULL, 0, 1);
251 
252 	return(0);
253 }
254 
pmc_stop(void * data)255 void pmc_stop(void *data)
256 {
257 	/* Freeze all counters, leave everything else alone */
258 	mtspr(MMCR0, mfspr( MMCR0 ) | 0x80000000);
259 }
260 
pmc_clear(void * data)261 void pmc_clear(void *data)
262 {
263 	mtspr(PMC1, 0); mtspr(PMC2, 0);
264 	mtspr(PMC3, 0); mtspr(PMC4, 0);
265 	mtspr(PMC5, 0); mtspr(PMC6, 0);
266 	mtspr(PMC7, 0); mtspr(PMC8, 0);
267 	mtspr(MMCR0, 0); mtspr(MMCR1, 0); mtspr(MMCRA, 0);
268 }
269 
pmc_start(void * data)270 void pmc_start(void *data)
271 {
272 	/* Free all counters, leave everything else alone */
273 	mtspr(MMCR0, mfspr( MMCR0 ) & 0x7fffffff);
274 }
275 
pmc_touch_bolted(void * data)276 void pmc_touch_bolted(void *data)
277 {
278 	volatile int touch;
279 
280 	/* Hack to fault the buffer into the segment table */
281 	touch = *((int *)(perfmon_base.profile_buffer));
282 }
283 
perfmon_dump_ctl(void * data)284 int perfmon_dump_ctl(void *data) {
285 	struct perfmon_struct *pdata;
286 	int err;
287 
288 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
289 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
290 
291 	switch(pdata->header.subcmd) {
292 	case PMC_SUBCMD_DUMP_COUNTERS:
293 		dump_pmc_struct(pdata);
294 		// copy_to_user(data, pdata, sizeof(struct perfmon_struct));
295 		break;
296 	case PMC_SUBCMD_DUMP_HARDWARE:
297 		dump_hardware_pmc_struct(pdata);
298 		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
299 		break;
300 	}
301 
302 	return(0);
303 }
304 
dump_pmc_struct(struct perfmon_struct * perfdata)305 void dump_pmc_struct(struct perfmon_struct *perfdata)
306 {
307 	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
308 
309 	if(cpu > MAX_PACAS) return;
310 
311 	printk("PMC Control Mode: 0x%lx\n", perfmon_base.state);
312 	printk("PMC[1 - 2] = 0x%16.16lx 0x%16.16lx\n",
313 	       paca[cpu].pmcc[0], paca[cpu].pmcc[1]);
314 	printk("PMC[3 - 4] = 0x%16.16lx 0x%16.16lx\n",
315 	       paca[cpu].pmcc[2], paca[cpu].pmcc[3]);
316 	printk("PMC[5 - 6] = 0x%16.16lx 0x%16.16lx\n",
317 	       paca[cpu].pmcc[4], paca[cpu].pmcc[5]);
318 	printk("PMC[7 - 8] = 0x%16.16lx 0x%16.16lx\n",
319 	       paca[cpu].pmcc[6], paca[cpu].pmcc[7]);
320 
321 	perfdata->vdata.pmc_info.mode = perfmon_base.state;
322 	for(i = 0; i < 11; i++)
323 		perfdata->vdata.pmc_info.pmc_base[i]  = paca[cpu].pmc[i];
324 
325 	for(i = 0; i < 8; i++)
326 		perfdata->vdata.pmc_info.pmc_cumulative[i]  = paca[cpu].pmcc[i];
327 }
328 
dump_hardware_pmc_struct(void * perfdata)329 void dump_hardware_pmc_struct(void *perfdata)
330 {
331 	unsigned int cpu = smp_processor_id();
332 
333 	printk("PMC[%2.2d][1 - 4]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
334 	       cpu, (u32) mfspr(PMC1),(u32) mfspr(PMC2),(u32) mfspr(PMC3),(u32) mfspr(PMC4));
335 	printk("PMC[%2.2d][5 - 8]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
336 	       cpu, (u32) mfspr(PMC5),(u32) mfspr(PMC6),(u32) mfspr(PMC7),(u32) mfspr(PMC8));
337 	printk("MMCR[%2.2d][0,1,A] = 0x%8.8x 0x%8.8x 0x%8.8x\n",
338 	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
339 }
340 
decr_profile(void * data)341 int decr_profile(void *data)
342 {
343 	int i;
344 
345 	printk("Perfmon: NIA decrementer profile\n");
346 
347 	if(perfmon_base.state == PMC_STATE_INITIAL) {
348 		printk("Perfmon: failed - no buffer was allocated.\n");
349 		return -1;
350 	}
351 
352 	/* Stop counters on all processors -- blocking */
353 	pmc_stop(NULL);
354 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
355 
356 	for (i=0; i<MAX_PACAS; ++i) {
357 		paca[i].prof_mode = PMC_STATE_DECR_PROFILE;
358 	}
359 
360 	perfmon_base.state = PMC_STATE_DECR_PROFILE;
361 	mb();
362 
363 	return 0;
364 }
365 
perfmon_profile_ctl(void * data)366 int perfmon_profile_ctl(void *data) {
367 	struct perfmon_struct *pdata;
368 	int err;
369 
370 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
371 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
372 
373 	switch(pdata->header.subcmd) {
374 	case PMC_SUBCMD_PROFILE_CYCLE:
375 		pmc_profile(pdata);
376 		break;
377 	default:
378 		return(-1);
379 	}
380 
381 	return(0);
382 }
383 
perfmon_trace_ctl(void * data)384 int perfmon_trace_ctl(void *data) {
385 	struct perfmon_struct *pdata;
386 	int err;
387 
388 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
389 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
390 
391 	pmc_set_general(pdata);
392 
393 #if 0
394         /* Reimplement at some point ... */
395 	pmc_set_user_general(pdata);
396 #endif
397 	return(0);
398 }
399 
perfmon_timeslice_ctl(void * data)400 int perfmon_timeslice_ctl(void *data) {
401 	struct perfmon_struct *pdata;
402 	int err;
403 
404 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
405 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
406 
407 	switch(pdata->header.subcmd) {
408 	case PMC_SUBCMD_TIMESLICE_ENABLE:
409 		pmc_timeslice_enable(pdata);
410 		break;
411 	case PMC_SUBCMD_TIMESLICE_DISABLE:
412 		pmc_timeslice_disable(pdata);
413 		break;
414 	case PMC_SUBCMD_TIMESLICE_SET:
415 		pmc_timeslice_set(pdata);
416 		break;
417 	default:
418 		return(-1);
419 	}
420 
421 	return(0);
422 }
423 
plpar_perfmon(int mode)424 static long plpar_perfmon(int mode)
425 {
426         return plpar_hcall_norets(H_PERFMON, mode, 0);
427 }
428 
pmc_configure_hardware()429 static void pmc_configure_hardware() {
430 	/*
431 	 * Debug bus enabled is required on GP for timeslice mode.
432 	 * Flood enabled is required on GP for PMC cycle profile mode
433 	 *   iSeries SP sets this by default.  pSeries requires the OS to enable.
434 	 */
435 	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
436 		/* Set up the debug bus to pmc mode - a feature of GP */
437 		switch(systemcfg->platform) {
438 		case PLATFORM_ISERIES_LPAR:
439 			HvCall_setDebugBus(1);
440 			break;
441 		case PLATFORM_PSERIES_LPAR:
442 			plpar_perfmon(1);
443 			break;
444 		case PLATFORM_PSERIES:
445 			mtspr(HID0, mfspr(HID0) | 0x0000080000000000);
446 		}
447 	}
448 }
449 
450 /*
451  * pmc_profile
452  *
453  * Profile the kernel based on cycle counts.  This is made a special case of the more
454  * general trace functions because it is high use.  Benefits of special casing this
455  * include a buffer of sufficient size to profile the entire kernel is available, and CPI
456  * can be collected along with the profile.
457  */
pmc_profile(struct perfmon_struct * perfdata)458 int pmc_profile(struct perfmon_struct *perfdata)
459 {
460 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
461 	int i;
462 
463 	printk("Perfmon: NIA PMC profile\n");
464 
465 	pmc_timeslice_disable(NULL); // fixme
466 
467 	if(perfmon_base.state == PMC_STATE_INITIAL) {
468 		printk("Perfmon: failed - no buffer was allocated.\n");
469 		return -1;
470 	}
471 
472 	/* Stop counters on all processors -- blocking */
473 	pmc_stop(NULL);
474 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
475 
476 	for (i=0; i<MAX_PACAS; ++i) {
477 		paca[i].prof_mode = PMC_STATE_PROFILE_KERN;
478 	}
479 	perfmon_base.state = PMC_STATE_PROFILE_KERN;
480 
481 	if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
482 		for(i = 0; i < 8; i++)
483 			pdata->pmc[i] = 0x0;
484 		pdata->pmc[1] = 0x7f000000;
485 		/* Freeze in problem state, exception enable, freeze on event, */
486 		/*   enable counter negative condition, PMC1, PMC2             */
487 		pdata->pmc[8] = 0x2600cd0e;
488 		pdata->pmc[9] = 0x4a5675ac;
489 
490 		/* Freeze while in wait state */
491 		pdata->pmc[10] = 0x00022002;
492 	} else {
493 		pdata->pmc[0] = 0x7f000000;
494 		for(i = 1; i < 8; i++)
495 			pdata->pmc[i] = 0x0;
496 		pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
497 		pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
498 
499 		/* Freeze while in wait state */
500 		pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
501 	}
502 
503 	pmc_configure_hardware();
504 
505 	mb();
506 
507 	pmc_trace_rec_type(perfdata->header.vdata.type);
508 	pmc_configure((void *)perfdata);
509 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
510 
511 	return 0;
512 }
513 
pmc_set_general(struct perfmon_struct * perfdata)514 int pmc_set_general(struct perfmon_struct *perfdata)
515 {
516 	int i;
517 
518 	printk("Perfmon: PMC sampling - General\n");
519 
520 	if(perfmon_base.state == PMC_STATE_INITIAL) {
521 		printk("Perfmon: failed - no buffer was allocated.\n");
522 		return -1;
523 	}
524 
525 	/* Stop counters on all processors -- blocking */
526 	pmc_stop(NULL);
527 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
528 
529 	for (i=0; i<MAX_PACAS; ++i) {
530 		paca[i].prof_mode = PMC_STATE_TRACE_KERN;
531 	}
532 	perfmon_base.state = PMC_STATE_TRACE_KERN;
533 	mb();
534 
535 	pmc_trace_rec_type(perfdata->header.vdata.type);
536 	pmc_configure((void *)perfdata);
537 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
538 
539 	return 0;
540 }
541 
pmc_set_user_general(struct perfmon_struct * perfdata)542 int pmc_set_user_general(struct perfmon_struct *perfdata)
543 {
544 #if 0
545 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
546 #endif
547 	int pid = perfdata->header.vdata.pid;
548 	struct task_struct *task;
549 	int i;
550 
551 	printk("Perfmon: PMC sampling - general user\n");
552 
553 	if(perfmon_base.state == PMC_STATE_INITIAL) {
554 		printk("Perfmon: failed - no buffer was allocated.\n");
555 		return -1;
556 	}
557 
558 	if(pid) {
559 		printk("Perfmon: pid = 0x%x\n", pid);
560 		read_lock(&tasklist_lock);
561 		task = find_task_by_pid(pid);
562 		if (task) {
563 			printk("Perfmon: task = 0x%lx\n", (u64) task);
564 			task->thread.regs->msr |= 0x4;
565 #if 0
566 			for(i = 0; i < 11; i++)
567 				task->thread.pmc[i] = pdata->pmc[i];
568 #endif
569 		} else {
570 			printk("Perfmon: task not found\n");
571 			read_unlock(&tasklist_lock);
572 			return -1;
573 		}
574 	}
575 	read_unlock(&tasklist_lock);
576 
577 	/* Stop counters on all processors -- blocking */
578 	pmc_stop(NULL);
579 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
580 
581 	for (i=0; i<MAX_PACAS; ++i) {
582 		paca[i].prof_mode = PMC_STATE_TRACE_USER;
583 	}
584 	perfmon_base.state = PMC_STATE_TRACE_USER;
585 	mb();
586 
587 	pmc_trace_rec_type(perfdata->header.vdata.type);
588 	pmc_configure((void *)perfdata);
589 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
590 
591 	return 0;
592 }
593 
pmc_trace_rec_type(unsigned long type)594 void pmc_trace_rec_type(unsigned long type)
595 {
596 	unsigned long cmd_rec;
597 
598 	cmd_rec = 0xFFUL << 56;
599 	cmd_rec |= type;
600 	*((unsigned long *)(perfmon_base.trace_buffer +
601 			    perfmon_base.trace_end)) = cmd_rec;
602 	perfmon_base.trace_end += 8;
603 	if(perfmon_base.trace_end >= perfmon_base.trace_length)
604 		perfmon_base.trace_end = 0;
605 }
606 
pmc_configure(void * data)607 void pmc_configure(void *data)
608 {
609 	struct paca_struct *lpaca = get_paca();
610 	struct perfmon_struct *perfdata = (struct perfmon_struct *)data;
611 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
612 	unsigned long i;
613 
614 	/* Indicate to hypervisor that we are using the PMCs */
615 	if(systemcfg->platform == PLATFORM_ISERIES_LPAR)
616 		lpaca->xLpPacaPtr->xPMCRegsInUse = 1;
617 
618 	/* Freeze all counters */
619 	mtspr(MMCR0, 0x80000000); mtspr(MMCR1, 0x00000000);
620 
621 	/* Clear all the PMCs */
622 	mtspr(PMC1, 0); mtspr(PMC2, 0); mtspr(PMC3, 0); mtspr(PMC4, 0);
623 	mtspr(PMC5, 0); mtspr(PMC6, 0); mtspr(PMC7, 0); mtspr(PMC8, 0);
624 
625 	/* Set the PMCs to the new values */
626 	for(i = 0; i < 11; i++) {
627 		lpaca->pmc[i]  = pdata->pmc[i];
628 		printk("pmc_configure: 0x%lx\n", pdata->pmc[i]);
629 	}
630 
631 	mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
632 	mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
633 	mtspr(PMC5, lpaca->pmc[4]); mtspr(PMC6, lpaca->pmc[5]);
634 	mtspr(PMC7, lpaca->pmc[6]); mtspr(PMC8, lpaca->pmc[7]);
635 	mtspr(MMCR1, lpaca->pmc[9]); mtspr(MMCRA, lpaca->pmc[10]);
636 
637 	mb();
638 
639 	/* Start all counters - MMCR0 contains the PMC enable control bit */
640 	mtspr(MMCR0, lpaca->pmc[8]);
641 }
642 
643 /* Increment the timeslice counters for the current timeslice */
pmc_timeslice_data_collect(void * data)644 void pmc_timeslice_data_collect(void *data) {
645 	struct paca_struct *lpaca = get_paca();
646 	int i, cpu = smp_processor_id();
647 	int slice_rec = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
648 		        pmc_timeslice[cpu]*PMC_MAX_COUNTERS;
649 
650 	/* First get any cumulative data that may have accrued */
651 	for(i=0; i<8; i++) {
652 		pmc_timeslice_data[slice_rec + i] += lpaca->pmcc[i];
653 		lpaca->pmcc[i] = 0;
654 		lpaca->pmc[i]  = 0;
655 	}
656 
657 	/* Next get current hardware values */
658 	pmc_timeslice_data[slice_rec + 0] += ((u32)mfspr(PMC1));
659 	pmc_timeslice_data[slice_rec + 1] += ((u32)mfspr(PMC2));
660 	pmc_timeslice_data[slice_rec + 2] += ((u32)mfspr(PMC3));
661 	pmc_timeslice_data[slice_rec + 3] += ((u32)mfspr(PMC4));
662 	pmc_timeslice_data[slice_rec + 4] += ((u32)mfspr(PMC5));
663 	pmc_timeslice_data[slice_rec + 5] += ((u32)mfspr(PMC6));
664 	pmc_timeslice_data[slice_rec + 6] += ((u32)mfspr(PMC7));
665 	pmc_timeslice_data[slice_rec + 7] += ((u32)mfspr(PMC8));
666 }
667 
668 /* Handle a timeslice tick.  Each processor executes independantly */
pmc_timeslice_tick()669 int pmc_timeslice_tick() {
670 	int i;
671 	struct perfmon_struct perfdata;
672 	unsigned int cpu = smp_processor_id();
673 
674 	/* Switch timeslice every decrementer, reduced by some factor */
675 	pmc_tick_count[cpu]++;
676 	if(!pmc_timeslice_enabled || pmc_tick_count[cpu] < PMC_TICK_FACTOR)
677 		return 0;
678 	pmc_tick_count[cpu] = 0;
679 
680 	/* Stop counters and collect current state */
681 	pmc_stop(NULL);
682 	pmc_timeslice_data_collect(NULL);
683 
684 	/* Move on to the next timeslice */
685 	pmc_timeslice[cpu]++;
686 	if(pmc_timeslice[cpu] >= pmc_timeslice_top) pmc_timeslice[cpu] = 0;
687 
688 	/* Set up the counters to reflect the new data to collect */
689 	for(i = 0; i < 8; i++) {
690 		perfdata.vdata.pmc.pmc[i] = 0;
691 	}
692 	for(i = 0; i < 3; i++) {
693 		perfdata.vdata.pmc.pmc[i+8] =
694 			pmc_timeslice_config[pmc_timeslice[cpu]*5+i];
695 	}
696 	mb();
697 
698 	/* Configure the new counters */
699 	pmc_configure((void *)&perfdata);
700 
701 	return 0;
702 }
703 
pmc_timeslice_set(struct perfmon_struct * perfdata)704 int pmc_timeslice_set(struct perfmon_struct *perfdata)
705 {
706 	int slice;
707 
708 	printk("Perfmon: Timeslice set\n");
709 
710 	slice = perfdata->header.vdata.slice;
711 	if(slice >= PMC_SLICES_MAX) {
712 		printk("Perfmon: invalid timeslice specified %d\n", slice);
713 		return(-1);
714 	}
715 
716 	if(slice > pmc_timeslice_top) pmc_timeslice_top = slice;
717 
718 	pmc_timeslice_config[slice * 5 + 0] = perfdata->vdata.pmc.pmc[0];
719 	pmc_timeslice_config[slice * 5 + 1] = perfdata->vdata.pmc.pmc[1];
720 	pmc_timeslice_config[slice * 5 + 2] = perfdata->vdata.pmc.pmc[2];
721 	pmc_timeslice_config[slice * 5 + 3] = perfdata->vdata.pmc.pmc[3];
722 	pmc_timeslice_config[slice * 5 + 4] = perfdata->vdata.pmc.pmc[4];
723 }
724 
pmc_timeslice_enable(struct perfmon_struct * perfdata)725 int pmc_timeslice_enable(struct perfmon_struct *perfdata)
726 {
727 	int i, j;
728 
729 	printk("Perfmon: Timeslice mode\n");
730 
731 	if(perfmon_base.state == PMC_STATE_INITIAL) {
732 		printk("Perfmon: failed - no buffer was allocated.\n");
733 		return -1;
734 	}
735 
736 	pmc_timeslice_disable(NULL); // fixme
737 	mb();
738 
739 	for (i=0; i<MAX_PACAS; ++i) {
740 		paca[i].prof_mode = PMC_STATE_TIMESLICE;
741 	}
742 	perfmon_base.state = PMC_STATE_TIMESLICE;
743 
744 	pmc_configure_hardware();
745 
746 	for(i=0; i<PMC_MAX_CPUS; i++) {
747 		pmc_tick_count[i] = 0;
748 		pmc_timeslice[i]  = 0;
749 	}
750 
751 	/* Stop counters on all processors -- blocking */
752 	pmc_stop(NULL);
753 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
754 
755 	/* Clear out the PMC counters, cumulative and current */
756 	for (i=0; i<MAX_PACAS; ++i) {
757 		paca[i].prof_mode = PMC_STATE_TIMESLICE;
758 		for(j=0; j<8; j++) {
759 			paca[i].pmcc[j] = 0;
760 		}
761 		for(j=0; j<11; j++) {
762 			paca[i].pmc[j] = 0;
763 		}
764 	}
765 
766 	memset((char *)perfmon_base.timeslice_buffer,
767 	       0, perfmon_base.timeslice_length);
768 
769 	pmc_trace_rec_type(PMC_TYPE_TIMESLICE);
770 
771 	/* Clear counters on all processors -- blocking */
772 	pmc_clear(NULL);
773 	smp_call_function(pmc_clear, (void *)NULL, 0, 1);
774 
775 	mb();
776 
777 	pmc_timeslice_enabled  = 1;
778 
779 	/*
780 	 * We do not actually setup the PMC hardware here.  That occurs
781 	 * after the first timeslice tick occurs. Close enough.
782 	 */
783 	return 0;
784 }
785 
pmc_timeslice_disable(struct perfmon_struct * perfdata)786 int pmc_timeslice_disable(struct perfmon_struct *perfdata)
787 {
788 	pmc_timeslice_enabled = 0;
789 }
790 
pmc_dump_timeslice(struct perfmon_struct * perfdata)791 void pmc_dump_timeslice(struct perfmon_struct *perfdata)
792 {
793 	unsigned long rec, i, j, idx;
794 	int cpu = smp_processor_id();
795 
796 	spin_lock(&pmc_lock);
797 
798 	pmc_trace_rec_type(PMC_TYPE_TIMESLICE_DUMP); /* DRENG put cpu num in */
799 	for(i=0; i<pmc_timeslice_top; i++) {
800 		for(j=0; j<8; j++) {
801 			idx = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
802 				i*PMC_MAX_COUNTERS + j;
803 			rec = pmc_timeslice_data[idx];
804 			*((unsigned long *)(perfmon_base.trace_buffer +
805 					    perfmon_base.trace_end)) = rec;
806 			perfmon_base.trace_end += 8;
807 			if(perfmon_base.trace_end >= perfmon_base.trace_length)
808 				perfmon_base.trace_end = 0;
809 		}
810 	}
811 	spin_unlock(&pmc_lock);
812 }
813