18c2ecf20Sopenharmony_ci/**
28c2ecf20Sopenharmony_ci * @file arch/alpha/oprofile/op_model_ev6.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * @remark Copyright 2002 OProfile authors
58c2ecf20Sopenharmony_ci * @remark Read the file COPYING
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * @author Richard Henderson <rth@twiddle.net>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/oprofile.h>
118c2ecf20Sopenharmony_ci#include <linux/smp.h>
128c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "op_impl.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Compute all of the registers in preparation for enabling profiling.  */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void
208c2ecf20Sopenharmony_ciev6_reg_setup(struct op_register_config *reg,
218c2ecf20Sopenharmony_ci	      struct op_counter_config *ctr,
228c2ecf20Sopenharmony_ci	      struct op_system_config *sys)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	unsigned long ctl, reset, need_reset, i;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	/* Select desired events.  We've mapped the event numbers
278c2ecf20Sopenharmony_ci	   such that they fit directly into the event selection fields.  */
288c2ecf20Sopenharmony_ci	ctl = 0;
298c2ecf20Sopenharmony_ci	if (ctr[0].enabled && ctr[0].event)
308c2ecf20Sopenharmony_ci		ctl |= (ctr[0].event & 1) << 4;
318c2ecf20Sopenharmony_ci	if (ctr[1].enabled)
328c2ecf20Sopenharmony_ci		ctl |= (ctr[1].event - 2) & 15;
338c2ecf20Sopenharmony_ci	reg->mux_select = ctl;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* Select logging options.  */
368c2ecf20Sopenharmony_ci	/* ??? Need to come up with some mechanism to trace only
378c2ecf20Sopenharmony_ci	   selected processes.  EV6 does not have a mechanism to
388c2ecf20Sopenharmony_ci	   select kernel or user mode only.  For now, enable always.  */
398c2ecf20Sopenharmony_ci	reg->proc_mode = 0;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* EV6 cannot change the width of the counters as with the
428c2ecf20Sopenharmony_ci	   other implementations.  But fortunately, we can write to
438c2ecf20Sopenharmony_ci	   the counters and set the value such that it will overflow
448c2ecf20Sopenharmony_ci	   at the right time.  */
458c2ecf20Sopenharmony_ci	reset = need_reset = 0;
468c2ecf20Sopenharmony_ci	for (i = 0; i < 2; ++i) {
478c2ecf20Sopenharmony_ci		unsigned long count = ctr[i].count;
488c2ecf20Sopenharmony_ci		if (!ctr[i].enabled)
498c2ecf20Sopenharmony_ci			continue;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		if (count > 0x100000)
528c2ecf20Sopenharmony_ci			count = 0x100000;
538c2ecf20Sopenharmony_ci		ctr[i].count = count;
548c2ecf20Sopenharmony_ci		reset |= (0x100000 - count) << (i ? 6 : 28);
558c2ecf20Sopenharmony_ci		if (count != 0x100000)
568c2ecf20Sopenharmony_ci			need_reset |= 1 << i;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	reg->reset_values = reset;
598c2ecf20Sopenharmony_ci	reg->need_reset = need_reset;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Program all of the registers in preparation for enabling profiling.  */
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void
658c2ecf20Sopenharmony_ciev6_cpu_setup (void *x)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct op_register_config *reg = x;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	wrperfmon(2, reg->mux_select);
708c2ecf20Sopenharmony_ci	wrperfmon(3, reg->proc_mode);
718c2ecf20Sopenharmony_ci	wrperfmon(6, reg->reset_values | 3);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/* CTR is a counter for which the user has requested an interrupt count
758c2ecf20Sopenharmony_ci   in between one of the widths selectable in hardware.  Reset the count
768c2ecf20Sopenharmony_ci   for CTR to the value stored in REG->RESET_VALUES.  */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic void
798c2ecf20Sopenharmony_ciev6_reset_ctr(struct op_register_config *reg, unsigned long ctr)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	wrperfmon(6, reg->reset_values | (1 << ctr));
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void
858c2ecf20Sopenharmony_ciev6_handle_interrupt(unsigned long which, struct pt_regs *regs,
868c2ecf20Sopenharmony_ci		     struct op_counter_config *ctr)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	/* Record the sample.  */
898c2ecf20Sopenharmony_ci	oprofile_add_sample(regs, which);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistruct op_axp_model op_model_ev6 = {
948c2ecf20Sopenharmony_ci	.reg_setup		= ev6_reg_setup,
958c2ecf20Sopenharmony_ci	.cpu_setup		= ev6_cpu_setup,
968c2ecf20Sopenharmony_ci	.reset_ctr		= ev6_reset_ctr,
978c2ecf20Sopenharmony_ci	.handle_interrupt	= ev6_handle_interrupt,
988c2ecf20Sopenharmony_ci	.cpu_type		= "alpha/ev6",
998c2ecf20Sopenharmony_ci	.num_counters		= 2,
1008c2ecf20Sopenharmony_ci	.can_set_proc_mode	= 0,
1018c2ecf20Sopenharmony_ci};
102