blob: 2297be406c61a5d78d473a2890bb755715a8f210 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/**
2 * arch/s390/oprofile/init.c
3 *
4 * S390 Version
Andreas Krebbeldd3c4672011-11-25 20:03:05 +01005 * Copyright (C) 2002-2011 IBM Deutschland Entwicklung GmbH, IBM Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
Heinz Graalfsc814d162011-02-15 13:02:14 -05007 * Author(s): Mahesh Salgaonkar (mahesh@linux.vnet.ibm.com)
8 * Author(s): Heinz Graalfs (graalfs@linux.vnet.ibm.com)
Andreas Krebbeldd3c4672011-11-25 20:03:05 +01009 * Author(s): Andreas Krebbel (krebbel@linux.vnet.ibm.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Heinz Graalfsc814d162011-02-15 13:02:14 -050011 * @remark Copyright 2002-2011 OProfile authors
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
14#include <linux/oprofile.h>
15#include <linux/init.h>
16#include <linux/errno.h>
Heinz Graalfsc814d162011-02-15 13:02:14 -050017#include <linux/fs.h>
Andreas Krebbeldd3c4672011-11-25 20:03:05 +010018#include <linux/module.h>
19#include <asm/processor.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Heinz Graalfsc814d162011-02-15 13:02:14 -050021#include "../../../drivers/oprofile/oprof.h"
Heiko Carstens984e8482011-03-23 10:15:00 +010022
23extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
24
25#ifdef CONFIG_64BIT
26
Heinz Graalfsc814d162011-02-15 13:02:14 -050027#include "hwsampler.h"
Andreas Krebbeldd3c4672011-11-25 20:03:05 +010028#include "op_counter.h"
Heinz Graalfsc814d162011-02-15 13:02:14 -050029
Christian Borntraeger68158232011-06-22 16:24:09 +020030#define DEFAULT_INTERVAL 4127518
Heinz Graalfsc814d162011-02-15 13:02:14 -050031
32#define DEFAULT_SDBT_BLOCKS 1
33#define DEFAULT_SDB_BLOCKS 511
34
35static unsigned long oprofile_hw_interval = DEFAULT_INTERVAL;
36static unsigned long oprofile_min_interval;
37static unsigned long oprofile_max_interval;
38
39static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS;
40static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS;
41
Andreas Krebbeldd3c4672011-11-25 20:03:05 +010042static int hwsampler_enabled;
Heinz Graalfsc814d162011-02-15 13:02:14 -050043static int hwsampler_running; /* start_mutex must be held to change */
Andreas Krebbeldd3c4672011-11-25 20:03:05 +010044static int hwsampler_available;
Heinz Graalfsc814d162011-02-15 13:02:14 -050045
46static struct oprofile_operations timer_ops;
Andreas Krebbeld0f4c162006-01-06 00:19:16 -080047
Andreas Krebbeldd3c4672011-11-25 20:03:05 +010048struct op_counter_config counter_config;
49
50enum __force_cpu_type {
51 reserved = 0, /* do not force */
52 timer,
53};
54static int force_cpu_type;
55
56static int set_cpu_type(const char *str, struct kernel_param *kp)
57{
58 if (!strcmp(str, "timer")) {
59 force_cpu_type = timer;
60 printk(KERN_INFO "oprofile: forcing timer to be returned "
61 "as cpu type\n");
62 } else {
63 force_cpu_type = 0;
64 }
65
66 return 0;
67}
68module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
69MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling"
70 "(report cpu_type \"timer\"");
71
Heinz Graalfsc814d162011-02-15 13:02:14 -050072static int oprofile_hwsampler_start(void)
73{
74 int retval;
75
Andreas Krebbeldd3c4672011-11-25 20:03:05 +010076 hwsampler_running = hwsampler_enabled;
Heinz Graalfsc814d162011-02-15 13:02:14 -050077
78 if (!hwsampler_running)
79 return timer_ops.start();
80
81 retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
82 if (retval)
83 return retval;
84
85 retval = hwsampler_start_all(oprofile_hw_interval);
86 if (retval)
87 hwsampler_deallocate();
88
89 return retval;
90}
91
92static void oprofile_hwsampler_stop(void)
93{
94 if (!hwsampler_running) {
95 timer_ops.stop();
96 return;
97 }
98
99 hwsampler_stop_all();
100 hwsampler_deallocate();
101 return;
102}
103
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100104/*
105 * File ops used for:
106 * /dev/oprofile/0/enabled
107 * /dev/oprofile/hwsampling/hwsampler (cpu_type = timer)
108 */
109
Heinz Graalfsc814d162011-02-15 13:02:14 -0500110static ssize_t hwsampler_read(struct file *file, char __user *buf,
111 size_t count, loff_t *offset)
112{
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100113 return oprofilefs_ulong_to_user(hwsampler_enabled, buf, count, offset);
Heinz Graalfsc814d162011-02-15 13:02:14 -0500114}
115
116static ssize_t hwsampler_write(struct file *file, char const __user *buf,
117 size_t count, loff_t *offset)
118{
119 unsigned long val;
120 int retval;
121
122 if (*offset)
123 return -EINVAL;
124
125 retval = oprofilefs_ulong_from_user(&val, buf, count);
Robert Richter913050b2011-12-19 16:38:30 +0100126 if (retval <= 0)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500127 return retval;
128
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100129 if (val != 0 && val != 1)
130 return -EINVAL;
131
Heinz Graalfsc814d162011-02-15 13:02:14 -0500132 if (oprofile_started)
133 /*
134 * save to do without locking as we set
135 * hwsampler_running in start() when start_mutex is
136 * held
137 */
138 return -EBUSY;
139
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100140 hwsampler_enabled = val;
Heinz Graalfsc814d162011-02-15 13:02:14 -0500141
142 return count;
143}
144
145static const struct file_operations hwsampler_fops = {
146 .read = hwsampler_read,
147 .write = hwsampler_write,
148};
149
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100150/*
151 * File ops used for:
152 * /dev/oprofile/0/count
153 * /dev/oprofile/hwsampling/hw_interval (cpu_type = timer)
154 *
155 * Make sure that the value is within the hardware range.
156 */
157
158static ssize_t hw_interval_read(struct file *file, char __user *buf,
159 size_t count, loff_t *offset)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500160{
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100161 return oprofilefs_ulong_to_user(oprofile_hw_interval, buf,
162 count, offset);
163}
Heinz Graalfsc814d162011-02-15 13:02:14 -0500164
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100165static ssize_t hw_interval_write(struct file *file, char const __user *buf,
166 size_t count, loff_t *offset)
167{
168 unsigned long val;
169 int retval;
Heinz Graalfsc814d162011-02-15 13:02:14 -0500170
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100171 if (*offset)
172 return -EINVAL;
173 retval = oprofilefs_ulong_from_user(&val, buf, count);
174 if (retval)
175 return retval;
176 if (val < oprofile_min_interval)
177 oprofile_hw_interval = oprofile_min_interval;
178 else if (val > oprofile_max_interval)
179 oprofile_hw_interval = oprofile_max_interval;
180 else
181 oprofile_hw_interval = val;
182
183 return count;
184}
185
186static const struct file_operations hw_interval_fops = {
187 .read = hw_interval_read,
188 .write = hw_interval_write,
189};
190
191/*
192 * File ops used for:
193 * /dev/oprofile/0/event
194 * Only a single event with number 0 is supported with this counter.
195 *
196 * /dev/oprofile/0/unit_mask
197 * This is a dummy file needed by the user space tools.
198 * No value other than 0 is accepted or returned.
199 */
200
201static ssize_t hwsampler_zero_read(struct file *file, char __user *buf,
202 size_t count, loff_t *offset)
203{
204 return oprofilefs_ulong_to_user(0, buf, count, offset);
205}
206
207static ssize_t hwsampler_zero_write(struct file *file, char const __user *buf,
208 size_t count, loff_t *offset)
209{
210 unsigned long val;
211 int retval;
212
213 if (*offset)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500214 return -EINVAL;
215
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100216 retval = oprofilefs_ulong_from_user(&val, buf, count);
217 if (retval)
218 return retval;
219 if (val != 0)
220 return -EINVAL;
221 return count;
222}
Heinz Graalfsc814d162011-02-15 13:02:14 -0500223
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100224static const struct file_operations zero_fops = {
225 .read = hwsampler_zero_read,
226 .write = hwsampler_zero_write,
227};
228
229/* /dev/oprofile/0/kernel file ops. */
230
231static ssize_t hwsampler_kernel_read(struct file *file, char __user *buf,
232 size_t count, loff_t *offset)
233{
234 return oprofilefs_ulong_to_user(counter_config.kernel,
235 buf, count, offset);
236}
237
238static ssize_t hwsampler_kernel_write(struct file *file, char const __user *buf,
239 size_t count, loff_t *offset)
240{
241 unsigned long val;
242 int retval;
243
244 if (*offset)
245 return -EINVAL;
246
247 retval = oprofilefs_ulong_from_user(&val, buf, count);
248 if (retval)
249 return retval;
250
251 if (val != 0 && val != 1)
252 return -EINVAL;
253
254 counter_config.kernel = val;
255
256 return count;
257}
258
259static const struct file_operations kernel_fops = {
260 .read = hwsampler_kernel_read,
261 .write = hwsampler_kernel_write,
262};
263
264/* /dev/oprofile/0/user file ops. */
265
266static ssize_t hwsampler_user_read(struct file *file, char __user *buf,
267 size_t count, loff_t *offset)
268{
269 return oprofilefs_ulong_to_user(counter_config.user,
270 buf, count, offset);
271}
272
273static ssize_t hwsampler_user_write(struct file *file, char const __user *buf,
274 size_t count, loff_t *offset)
275{
276 unsigned long val;
277 int retval;
278
279 if (*offset)
280 return -EINVAL;
281
282 retval = oprofilefs_ulong_from_user(&val, buf, count);
283 if (retval)
284 return retval;
285
286 if (val != 0 && val != 1)
287 return -EINVAL;
288
289 counter_config.user = val;
290
291 return count;
292}
293
294static const struct file_operations user_fops = {
295 .read = hwsampler_user_read,
296 .write = hwsampler_user_write,
297};
298
299
300/*
301 * File ops used for: /dev/oprofile/timer/enabled
302 * The value always has to be the inverted value of hwsampler_enabled. So
303 * no separate variable is created. That way we do not need locking.
304 */
305
306static ssize_t timer_enabled_read(struct file *file, char __user *buf,
307 size_t count, loff_t *offset)
308{
309 return oprofilefs_ulong_to_user(!hwsampler_enabled, buf, count, offset);
310}
311
312static ssize_t timer_enabled_write(struct file *file, char const __user *buf,
313 size_t count, loff_t *offset)
314{
315 unsigned long val;
316 int retval;
317
318 if (*offset)
319 return -EINVAL;
320
321 retval = oprofilefs_ulong_from_user(&val, buf, count);
322 if (retval)
323 return retval;
324
325 if (val != 0 && val != 1)
326 return -EINVAL;
327
328 /* Timer cannot be disabled without having hardware sampling. */
329 if (val == 0 && !hwsampler_available)
330 return -EINVAL;
331
332 if (oprofile_started)
333 /*
334 * save to do without locking as we set
335 * hwsampler_running in start() when start_mutex is
336 * held
337 */
338 return -EBUSY;
339
340 hwsampler_enabled = !val;
341
342 return count;
343}
344
345static const struct file_operations timer_enabled_fops = {
346 .read = timer_enabled_read,
347 .write = timer_enabled_write,
348};
349
350
351static int oprofile_create_hwsampling_files(struct super_block *sb,
352 struct dentry *root)
353{
354 struct dentry *dir;
355
356 dir = oprofilefs_mkdir(sb, root, "timer");
357 if (!dir)
358 return -EINVAL;
359
360 oprofilefs_create_file(sb, dir, "enabled", &timer_enabled_fops);
361
362 if (!hwsampler_available)
363 return 0;
364
365 /* reinitialize default values */
366 hwsampler_enabled = 1;
367 counter_config.kernel = 1;
368 counter_config.user = 1;
369
370 if (!force_cpu_type) {
371 /*
372 * Create the counter file system. A single virtual
373 * counter is created which can be used to
374 * enable/disable hardware sampling dynamically from
375 * user space. The user space will configure a single
376 * counter with a single event. The value of 'event'
377 * and 'unit_mask' are not evaluated by the kernel code
378 * and can only be set to 0.
379 */
380
381 dir = oprofilefs_mkdir(sb, root, "0");
382 if (!dir)
383 return -EINVAL;
384
385 oprofilefs_create_file(sb, dir, "enabled", &hwsampler_fops);
386 oprofilefs_create_file(sb, dir, "event", &zero_fops);
387 oprofilefs_create_file(sb, dir, "count", &hw_interval_fops);
388 oprofilefs_create_file(sb, dir, "unit_mask", &zero_fops);
389 oprofilefs_create_file(sb, dir, "kernel", &kernel_fops);
390 oprofilefs_create_file(sb, dir, "user", &user_fops);
391 oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks",
392 &oprofile_sdbt_blocks);
393
394 } else {
395 /*
396 * Hardware sampling can be used but the cpu_type is
397 * forced to timer in order to deal with legacy user
398 * space tools. The /dev/oprofile/hwsampling fs is
399 * provided in that case.
400 */
401 dir = oprofilefs_mkdir(sb, root, "hwsampling");
402 if (!dir)
403 return -EINVAL;
404
405 oprofilefs_create_file(sb, dir, "hwsampler",
406 &hwsampler_fops);
407 oprofilefs_create_file(sb, dir, "hw_interval",
408 &hw_interval_fops);
409 oprofilefs_create_ro_ulong(sb, dir, "hw_min_interval",
410 &oprofile_min_interval);
411 oprofilefs_create_ro_ulong(sb, dir, "hw_max_interval",
412 &oprofile_max_interval);
413 oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks",
414 &oprofile_sdbt_blocks);
415 }
Heinz Graalfsc814d162011-02-15 13:02:14 -0500416 return 0;
417}
418
Robert Richterec6b4262011-03-16 12:10:12 +0100419static int oprofile_hwsampler_init(struct oprofile_operations *ops)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500420{
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100421 /*
422 * Initialize the timer mode infrastructure as well in order
423 * to be able to switch back dynamically. oprofile_timer_init
424 * is not supposed to fail.
425 */
426 if (oprofile_timer_init(ops))
427 BUG();
428
429 memcpy(&timer_ops, ops, sizeof(timer_ops));
430 ops->create_files = oprofile_create_hwsampling_files;
431
432 /*
433 * If the user space tools do not support newer cpu types,
434 * the force_cpu_type module parameter
435 * can be used to always return \"timer\" as cpu type.
436 */
437 if (force_cpu_type != timer) {
438 struct cpuid id;
439
440 get_cpu_id (&id);
441
442 switch (id.machine) {
443 case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break;
444 case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break;
445 default: return -ENODEV;
446 }
447 }
448
Heinz Graalfsc814d162011-02-15 13:02:14 -0500449 if (hwsampler_setup())
450 return -ENODEV;
451
452 /*
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100453 * Query the range for the sampling interval from the
454 * hardware.
Heinz Graalfsc814d162011-02-15 13:02:14 -0500455 */
456 oprofile_min_interval = hwsampler_query_min_interval();
Martin Schwidefsky3d8dcb32011-05-10 17:13:42 +0200457 if (oprofile_min_interval == 0)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500458 return -ENODEV;
Heinz Graalfsc814d162011-02-15 13:02:14 -0500459 oprofile_max_interval = hwsampler_query_max_interval();
Martin Schwidefsky3d8dcb32011-05-10 17:13:42 +0200460 if (oprofile_max_interval == 0)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500461 return -ENODEV;
Heinz Graalfsc814d162011-02-15 13:02:14 -0500462
Christian Borntraegerb530ce72011-06-22 16:24:08 +0200463 /* The initial value should be sane */
464 if (oprofile_hw_interval < oprofile_min_interval)
465 oprofile_hw_interval = oprofile_min_interval;
466 if (oprofile_hw_interval > oprofile_max_interval)
467 oprofile_hw_interval = oprofile_max_interval;
468
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100469 printk(KERN_INFO "oprofile: System z hardware sampling "
470 "facility found.\n");
Heinz Graalfsc814d162011-02-15 13:02:14 -0500471
472 ops->start = oprofile_hwsampler_start;
473 ops->stop = oprofile_hwsampler_stop;
Heinz Graalfsc814d162011-02-15 13:02:14 -0500474
475 return 0;
476}
477
Robert Richterec6b4262011-03-16 12:10:12 +0100478static void oprofile_hwsampler_exit(void)
Heinz Graalfsc814d162011-02-15 13:02:14 -0500479{
Heinz Graalfsc814d162011-02-15 13:02:14 -0500480 hwsampler_shutdown();
481}
482
Heiko Carstens984e8482011-03-23 10:15:00 +0100483#endif /* CONFIG_64BIT */
484
Robert Richterec6b4262011-03-16 12:10:12 +0100485int __init oprofile_arch_init(struct oprofile_operations *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Andreas Krebbeld0f4c162006-01-06 00:19:16 -0800487 ops->backtrace = s390_backtrace;
Heinz Graalfs997dbb42011-01-21 10:06:53 +0000488
Heiko Carstens984e8482011-03-23 10:15:00 +0100489#ifdef CONFIG_64BIT
Andreas Krebbeldd3c4672011-11-25 20:03:05 +0100490
491 /*
492 * -ENODEV is not reported to the caller. The module itself
493 * will use the timer mode sampling as fallback and this is
494 * always available.
495 */
496 hwsampler_available = oprofile_hwsampler_init(ops) == 0;
497
498 return 0;
Heiko Carstens984e8482011-03-23 10:15:00 +0100499#else
500 return -ENODEV;
501#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
504void oprofile_arch_exit(void)
505{
Heiko Carstens984e8482011-03-23 10:15:00 +0100506#ifdef CONFIG_64BIT
Heinz Graalfs997dbb42011-01-21 10:06:53 +0000507 oprofile_hwsampler_exit();
Heiko Carstens984e8482011-03-23 10:15:00 +0100508#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}