Linux Audio

Check our new training course

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