Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
init.c
Go to the documentation of this file.
1 /*
2  * S390 Version
3  * Copyright IBM Corp. 2002, 2011
4  * Author(s): Thomas Spatzier ([email protected])
5  * Author(s): Mahesh Salgaonkar ([email protected])
6  * Author(s): Heinz Graalfs ([email protected])
7  * Author(s): Andreas Krebbel ([email protected])
8  *
9  * @remark Copyright 2002-2011 OProfile authors
10  */
11 
12 #include <linux/oprofile.h>
13 #include <linux/init.h>
14 #include <linux/errno.h>
15 #include <linux/fs.h>
16 #include <linux/module.h>
17 #include <asm/processor.h>
18 
19 #include "../../../drivers/oprofile/oprof.h"
20 
21 extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
22 
23 #ifdef CONFIG_64BIT
24 
25 #include "hwsampler.h"
26 #include "op_counter.h"
27 
28 #define DEFAULT_INTERVAL 4127518
29 
30 #define DEFAULT_SDBT_BLOCKS 1
31 #define DEFAULT_SDB_BLOCKS 511
32 
33 static unsigned long oprofile_hw_interval = DEFAULT_INTERVAL;
34 static unsigned long oprofile_min_interval;
35 static unsigned long oprofile_max_interval;
36 
37 static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS;
38 static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS;
39 
40 static int hwsampler_enabled;
41 static int hwsampler_running; /* start_mutex must be held to change */
42 static int hwsampler_available;
43 
44 static struct oprofile_operations timer_ops;
45 
47 
48 enum __force_cpu_type {
49  reserved = 0, /* do not force */
50  timer,
51 };
52 static int force_cpu_type;
53 
54 static int set_cpu_type(const char *str, struct kernel_param *kp)
55 {
56  if (!strcmp(str, "timer")) {
57  force_cpu_type = timer;
58  printk(KERN_INFO "oprofile: forcing timer to be returned "
59  "as cpu type\n");
60  } else {
61  force_cpu_type = 0;
62  }
63 
64  return 0;
65 }
66 module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
67 MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling"
68  "(report cpu_type \"timer\"");
69 
70 static int oprofile_hwsampler_start(void)
71 {
72  int retval;
73 
74  hwsampler_running = hwsampler_enabled;
75 
76  if (!hwsampler_running)
77  return timer_ops.start();
78 
79  retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
80  if (retval)
81  return retval;
82 
83  retval = hwsampler_start_all(oprofile_hw_interval);
84  if (retval)
86 
87  return retval;
88 }
89 
90 static void oprofile_hwsampler_stop(void)
91 {
92  if (!hwsampler_running) {
93  timer_ops.stop();
94  return;
95  }
96 
99  return;
100 }
101 
102 /*
103  * File ops used for:
104  * /dev/oprofile/0/enabled
105  * /dev/oprofile/hwsampling/hwsampler (cpu_type = timer)
106  */
107 
108 static ssize_t hwsampler_read(struct file *file, char __user *buf,
109  size_t count, loff_t *offset)
110 {
111  return oprofilefs_ulong_to_user(hwsampler_enabled, buf, count, offset);
112 }
113 
114 static ssize_t hwsampler_write(struct file *file, char const __user *buf,
115  size_t count, loff_t *offset)
116 {
117  unsigned long val;
118  int retval;
119 
120  if (*offset)
121  return -EINVAL;
122 
123  retval = oprofilefs_ulong_from_user(&val, buf, count);
124  if (retval <= 0)
125  return retval;
126 
127  if (val != 0 && val != 1)
128  return -EINVAL;
129 
130  if (oprofile_started)
131  /*
132  * save to do without locking as we set
133  * hwsampler_running in start() when start_mutex is
134  * held
135  */
136  return -EBUSY;
137 
138  hwsampler_enabled = val;
139 
140  return count;
141 }
142 
143 static const struct file_operations hwsampler_fops = {
144  .read = hwsampler_read,
145  .write = hwsampler_write,
146 };
147 
148 /*
149  * File ops used for:
150  * /dev/oprofile/0/count
151  * /dev/oprofile/hwsampling/hw_interval (cpu_type = timer)
152  *
153  * Make sure that the value is within the hardware range.
154  */
155 
156 static ssize_t hw_interval_read(struct file *file, char __user *buf,
157  size_t count, loff_t *offset)
158 {
159  return oprofilefs_ulong_to_user(oprofile_hw_interval, buf,
160  count, offset);
161 }
162 
163 static ssize_t hw_interval_write(struct file *file, char const __user *buf,
164  size_t count, loff_t *offset)
165 {
166  unsigned long val;
167  int retval;
168 
169  if (*offset)
170  return -EINVAL;
171  retval = oprofilefs_ulong_from_user(&val, buf, count);
172  if (retval <= 0)
173  return retval;
174  if (val < oprofile_min_interval)
175  oprofile_hw_interval = oprofile_min_interval;
176  else if (val > oprofile_max_interval)
177  oprofile_hw_interval = oprofile_max_interval;
178  else
179  oprofile_hw_interval = val;
180 
181  return count;
182 }
183 
184 static const struct file_operations hw_interval_fops = {
185  .read = hw_interval_read,
186  .write = hw_interval_write,
187 };
188 
189 /*
190  * File ops used for:
191  * /dev/oprofile/0/event
192  * Only a single event with number 0 is supported with this counter.
193  *
194  * /dev/oprofile/0/unit_mask
195  * This is a dummy file needed by the user space tools.
196  * No value other than 0 is accepted or returned.
197  */
198 
199 static ssize_t hwsampler_zero_read(struct file *file, char __user *buf,
200  size_t count, loff_t *offset)
201 {
202  return oprofilefs_ulong_to_user(0, buf, count, offset);
203 }
204 
205 static ssize_t hwsampler_zero_write(struct file *file, char const __user *buf,
206  size_t count, loff_t *offset)
207 {
208  unsigned long val;
209  int retval;
210 
211  if (*offset)
212  return -EINVAL;
213 
214  retval = oprofilefs_ulong_from_user(&val, buf, count);
215  if (retval <= 0)
216  return retval;
217  if (val != 0)
218  return -EINVAL;
219  return count;
220 }
221 
222 static const struct file_operations zero_fops = {
223  .read = hwsampler_zero_read,
224  .write = hwsampler_zero_write,
225 };
226 
227 /* /dev/oprofile/0/kernel file ops. */
228 
229 static ssize_t hwsampler_kernel_read(struct file *file, char __user *buf,
230  size_t count, loff_t *offset)
231 {
233  buf, count, offset);
234 }
235 
236 static ssize_t hwsampler_kernel_write(struct file *file, char const __user *buf,
237  size_t count, loff_t *offset)
238 {
239  unsigned long val;
240  int retval;
241 
242  if (*offset)
243  return -EINVAL;
244 
245  retval = oprofilefs_ulong_from_user(&val, buf, count);
246  if (retval <= 0)
247  return retval;
248 
249  if (val != 0 && val != 1)
250  return -EINVAL;
251 
252  counter_config.kernel = val;
253 
254  return count;
255 }
256 
257 static const struct file_operations kernel_fops = {
258  .read = hwsampler_kernel_read,
259  .write = hwsampler_kernel_write,
260 };
261 
262 /* /dev/oprofile/0/user file ops. */
263 
264 static ssize_t hwsampler_user_read(struct file *file, char __user *buf,
265  size_t count, loff_t *offset)
266 {
268  buf, count, offset);
269 }
270 
271 static ssize_t hwsampler_user_write(struct file *file, char const __user *buf,
272  size_t count, loff_t *offset)
273 {
274  unsigned long val;
275  int retval;
276 
277  if (*offset)
278  return -EINVAL;
279 
280  retval = oprofilefs_ulong_from_user(&val, buf, count);
281  if (retval <= 0)
282  return retval;
283 
284  if (val != 0 && val != 1)
285  return -EINVAL;
286 
287  counter_config.user = val;
288 
289  return count;
290 }
291 
292 static const struct file_operations user_fops = {
293  .read = hwsampler_user_read,
294  .write = hwsampler_user_write,
295 };
296 
297 
298 /*
299  * File ops used for: /dev/oprofile/timer/enabled
300  * The value always has to be the inverted value of hwsampler_enabled. So
301  * no separate variable is created. That way we do not need locking.
302  */
303 
304 static ssize_t timer_enabled_read(struct file *file, char __user *buf,
305  size_t count, loff_t *offset)
306 {
307  return oprofilefs_ulong_to_user(!hwsampler_enabled, buf, count, offset);
308 }
309 
310 static ssize_t timer_enabled_write(struct file *file, char const __user *buf,
311  size_t count, loff_t *offset)
312 {
313  unsigned long val;
314  int retval;
315 
316  if (*offset)
317  return -EINVAL;
318 
319  retval = oprofilefs_ulong_from_user(&val, buf, count);
320  if (retval <= 0)
321  return retval;
322 
323  if (val != 0 && val != 1)
324  return -EINVAL;
325 
326  /* Timer cannot be disabled without having hardware sampling. */
327  if (val == 0 && !hwsampler_available)
328  return -EINVAL;
329 
330  if (oprofile_started)
331  /*
332  * save to do without locking as we set
333  * hwsampler_running in start() when start_mutex is
334  * held
335  */
336  return -EBUSY;
337 
338  hwsampler_enabled = !val;
339 
340  return count;
341 }
342 
343 static const struct file_operations timer_enabled_fops = {
344  .read = timer_enabled_read,
345  .write = timer_enabled_write,
346 };
347 
348 
349 static int oprofile_create_hwsampling_files(struct super_block *sb,
350  struct dentry *root)
351 {
352  struct dentry *dir;
353 
354  dir = oprofilefs_mkdir(sb, root, "timer");
355  if (!dir)
356  return -EINVAL;
357 
358  oprofilefs_create_file(sb, dir, "enabled", &timer_enabled_fops);
359 
360  if (!hwsampler_available)
361  return 0;
362 
363  /* reinitialize default values */
364  hwsampler_enabled = 1;
365  counter_config.kernel = 1;
366  counter_config.user = 1;
367 
368  if (!force_cpu_type) {
369  /*
370  * Create the counter file system. A single virtual
371  * counter is created which can be used to
372  * enable/disable hardware sampling dynamically from
373  * user space. The user space will configure a single
374  * counter with a single event. The value of 'event'
375  * and 'unit_mask' are not evaluated by the kernel code
376  * and can only be set to 0.
377  */
378 
379  dir = oprofilefs_mkdir(sb, root, "0");
380  if (!dir)
381  return -EINVAL;
382 
383  oprofilefs_create_file(sb, dir, "enabled", &hwsampler_fops);
384  oprofilefs_create_file(sb, dir, "event", &zero_fops);
385  oprofilefs_create_file(sb, dir, "count", &hw_interval_fops);
386  oprofilefs_create_file(sb, dir, "unit_mask", &zero_fops);
387  oprofilefs_create_file(sb, dir, "kernel", &kernel_fops);
388  oprofilefs_create_file(sb, dir, "user", &user_fops);
389  oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks",
390  &oprofile_sdbt_blocks);
391 
392  } else {
393  /*
394  * Hardware sampling can be used but the cpu_type is
395  * forced to timer in order to deal with legacy user
396  * space tools. The /dev/oprofile/hwsampling fs is
397  * provided in that case.
398  */
399  dir = oprofilefs_mkdir(sb, root, "hwsampling");
400  if (!dir)
401  return -EINVAL;
402 
403  oprofilefs_create_file(sb, dir, "hwsampler",
404  &hwsampler_fops);
405  oprofilefs_create_file(sb, dir, "hw_interval",
406  &hw_interval_fops);
407  oprofilefs_create_ro_ulong(sb, dir, "hw_min_interval",
408  &oprofile_min_interval);
409  oprofilefs_create_ro_ulong(sb, dir, "hw_max_interval",
410  &oprofile_max_interval);
411  oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks",
412  &oprofile_sdbt_blocks);
413  }
414  return 0;
415 }
416 
417 static int oprofile_hwsampler_init(struct oprofile_operations *ops)
418 {
419  /*
420  * Initialize the timer mode infrastructure as well in order
421  * to be able to switch back dynamically. oprofile_timer_init
422  * is not supposed to fail.
423  */
424  if (oprofile_timer_init(ops))
425  BUG();
426 
427  memcpy(&timer_ops, ops, sizeof(timer_ops));
428  ops->create_files = oprofile_create_hwsampling_files;
429 
430  /*
431  * If the user space tools do not support newer cpu types,
432  * the force_cpu_type module parameter
433  * can be used to always return \"timer\" as cpu type.
434  */
435  if (force_cpu_type != timer) {
436  struct cpuid id;
437 
438  get_cpu_id (&id);
439 
440  switch (id.machine) {
441  case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break;
442  case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break;
443  default: return -ENODEV;
444  }
445  }
446 
447  if (hwsampler_setup())
448  return -ENODEV;
449 
450  /*
451  * Query the range for the sampling interval from the
452  * hardware.
453  */
454  oprofile_min_interval = hwsampler_query_min_interval();
455  if (oprofile_min_interval == 0)
456  return -ENODEV;
457  oprofile_max_interval = hwsampler_query_max_interval();
458  if (oprofile_max_interval == 0)
459  return -ENODEV;
460 
461  /* The initial value should be sane */
462  if (oprofile_hw_interval < oprofile_min_interval)
463  oprofile_hw_interval = oprofile_min_interval;
464  if (oprofile_hw_interval > oprofile_max_interval)
465  oprofile_hw_interval = oprofile_max_interval;
466 
467  printk(KERN_INFO "oprofile: System z hardware sampling "
468  "facility found.\n");
469 
470  ops->start = oprofile_hwsampler_start;
471  ops->stop = oprofile_hwsampler_stop;
472 
473  return 0;
474 }
475 
476 static void oprofile_hwsampler_exit(void)
477 {
479 }
480 
481 #endif /* CONFIG_64BIT */
482 
484 {
485  ops->backtrace = s390_backtrace;
486 
487 #ifdef CONFIG_64BIT
488 
489  /*
490  * -ENODEV is not reported to the caller. The module itself
491  * will use the timer mode sampling as fallback and this is
492  * always available.
493  */
494  hwsampler_available = oprofile_hwsampler_init(ops) == 0;
495 
496  return 0;
497 #else
498  return -ENODEV;
499 #endif
500 }
501 
503 {
504 #ifdef CONFIG_64BIT
505  oprofile_hwsampler_exit();
506 #endif
507 }