Blame view

arch/alpha/oprofile/common.c 4.39 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  /**
   * @file arch/alpha/oprofile/common.c
   *
   * @remark Copyright 2002 OProfile authors
   * @remark Read the file COPYING
   *
   * @author Richard Henderson <rth@twiddle.net>
   */
  
  #include <linux/oprofile.h>
  #include <linux/init.h>
  #include <linux/smp.h>
  #include <linux/errno.h>
  #include <asm/ptrace.h>
  #include <asm/system.h>
  
  #include "op_impl.h"
  
  extern struct op_axp_model op_model_ev4 __attribute__((weak));
  extern struct op_axp_model op_model_ev5 __attribute__((weak));
  extern struct op_axp_model op_model_pca56 __attribute__((weak));
  extern struct op_axp_model op_model_ev6 __attribute__((weak));
  extern struct op_axp_model op_model_ev67 __attribute__((weak));
  
  static struct op_axp_model *model;
  
  extern void (*perf_irq)(unsigned long, struct pt_regs *);
  static void (*save_perf_irq)(unsigned long, struct pt_regs *);
  
  static struct op_counter_config ctr[20];
  static struct op_system_config sys;
  static struct op_register_config reg;
  
  /* Called from do_entInt to handle the performance monitor interrupt.  */
  
  static void
  op_handle_interrupt(unsigned long which, struct pt_regs *regs)
  {
  	model->handle_interrupt(which, regs, ctr);
  
  	/* If the user has selected an interrupt frequency that is
  	   not exactly the width of the counter, write a new value
  	   into the counter such that it'll overflow after N more
  	   events.  */
  	if ((reg.need_reset >> which) & 1)
  		model->reset_ctr(&reg, which);
  }
   
  static int
  op_axp_setup(void)
  {
  	unsigned long i, e;
  
  	/* Install our interrupt handler into the existing hook.  */
  	save_perf_irq = perf_irq;
  	perf_irq = op_handle_interrupt;
  
  	/* Compute the mask of enabled counters.  */
  	for (i = e = 0; i < model->num_counters; ++i)
  		if (ctr[i].enabled)
  			e |= 1 << i;
  	reg.enable = e;
  
  	/* Pre-compute the values to stuff in the hardware registers.  */
  	model->reg_setup(&reg, ctr, &sys);
  
  	/* Configure the registers on all cpus.  */
8691e5a8f   Jens Axboe   smp_call_function...
68
  	(void)smp_call_function(model->cpu_setup, &reg, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  	model->cpu_setup(&reg);
  	return 0;
  }
  
  static void
  op_axp_shutdown(void)
  {
  	/* Remove our interrupt handler.  We may be removing this module.  */
  	perf_irq = save_perf_irq;
  }
  
  static void
  op_axp_cpu_start(void *dummy)
  {
  	wrperfmon(1, reg.enable);
  }
  
  static int
  op_axp_start(void)
  {
8691e5a8f   Jens Axboe   smp_call_function...
89
  	(void)smp_call_function(op_axp_cpu_start, NULL, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  	op_axp_cpu_start(NULL);
  	return 0;
  }
  
  static inline void
  op_axp_cpu_stop(void *dummy)
  {
  	/* Disable performance monitoring for all counters.  */
  	wrperfmon(0, -1);
  }
  
  static void
  op_axp_stop(void)
  {
8691e5a8f   Jens Axboe   smp_call_function...
104
  	(void)smp_call_function(op_axp_cpu_stop, NULL, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
  	op_axp_cpu_stop(NULL);
  }
  
  static int
25ad2913c   Robert Richter   oprofile: more wh...
109
  op_axp_create_files(struct super_block *sb, struct dentry *root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
  {
  	int i;
  
  	for (i = 0; i < model->num_counters; ++i) {
  		struct dentry *dir;
0c6856f70   Markus Armbruster   [PATCH] oprofile:...
115
  		char buf[4];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  
  		snprintf(buf, sizeof buf, "%d", i);
  		dir = oprofilefs_mkdir(sb, root, buf);
  
  		oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
                  oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
  		oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
  		/* Dummies.  */
  		oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
  		oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
  		oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
  	}
  
  	if (model->can_set_proc_mode) {
  		oprofilefs_create_ulong(sb, root, "enable_pal",
  					&sys.enable_pal);
  		oprofilefs_create_ulong(sb, root, "enable_kernel",
  					&sys.enable_kernel);
  		oprofilefs_create_ulong(sb, root, "enable_user",
  					&sys.enable_user);
  	}
  
  	return 0;
  }
  
  int __init
  oprofile_arch_init(struct oprofile_operations *ops)
  {
  	struct op_axp_model *lmodel = NULL;
  
  	switch (implver()) {
  	case IMPLVER_EV4:
  		lmodel = &op_model_ev4;
  		break;
  	case IMPLVER_EV5:
  		/* 21164PC has a slightly different set of events.
  		   Recognize the chip by the presence of the MAX insns.  */
  		if (!amask(AMASK_MAX))
  			lmodel = &op_model_pca56;
  		else
  			lmodel = &op_model_ev5;
  		break;
  	case IMPLVER_EV6:
  		/* 21264A supports ProfileMe.
  		   Recognize the chip by the presence of the CIX insns.  */
  		if (!amask(AMASK_CIX))
  			lmodel = &op_model_ev67;
  		else
  			lmodel = &op_model_ev6;
  		break;
  	}
  
  	if (!lmodel)
  		return -ENODEV;
  	model = lmodel;
  
  	ops->create_files = op_axp_create_files;
  	ops->setup = op_axp_setup;
  	ops->shutdown = op_axp_shutdown;
  	ops->start = op_axp_start;
  	ops->stop = op_axp_stop;
  	ops->cpu_type = lmodel->cpu_type;
  
  	printk(KERN_INFO "oprofile: using %s performance monitoring.
  ",
  	       lmodel->cpu_type);
  
  	return 0;
  }
  
  
  void
  oprofile_arch_exit(void)
  {
  }