| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @file common.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @remark Copyright 2004 Oprofile Authors | 
					
						
							|  |  |  |  * @remark Read the file COPYING | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @author Zwane Mwaikambo | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/oprofile.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/sysdev.h>
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | #include <asm/semaphore.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "op_counter.h"
 | 
					
						
							|  |  |  | #include "op_arm_model.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static struct op_arm_model_spec *op_arm_model; | 
					
						
							|  |  |  | static int op_arm_enabled; | 
					
						
							|  |  |  | static struct semaphore op_arm_sem; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct op_counter_config counter_config[OP_MAX_COUNTER]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static int op_arm_create_files(struct super_block *sb, struct dentry *root) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	for (i = 0; i < op_arm_model->num_counters; i++) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		struct dentry *dir; | 
					
						
							|  |  |  | 		char buf[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		snprintf(buf, sizeof buf, "%d", i); | 
					
						
							|  |  |  | 		dir = oprofilefs_mkdir(sb, root, buf); | 
					
						
							|  |  |  | 		oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); | 
					
						
							|  |  |  | 		oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); | 
					
						
							|  |  |  | 		oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); | 
					
						
							|  |  |  | 		oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); | 
					
						
							|  |  |  | 		oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); | 
					
						
							|  |  |  | 		oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static int op_arm_setup(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&oprofilefs_lock); | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	ret = op_arm_model->setup_ctrs(); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	spin_unlock(&oprofilefs_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static int op_arm_start(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret = -EBUSY; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	down(&op_arm_sem); | 
					
						
							|  |  |  | 	if (!op_arm_enabled) { | 
					
						
							|  |  |  | 		ret = op_arm_model->start(); | 
					
						
							|  |  |  | 		op_arm_enabled = !ret; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	up(&op_arm_sem); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static void op_arm_stop(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	down(&op_arm_sem); | 
					
						
							|  |  |  | 	if (op_arm_enabled) | 
					
						
							|  |  |  | 		op_arm_model->stop(); | 
					
						
							|  |  |  | 	op_arm_enabled = 0; | 
					
						
							|  |  |  | 	up(&op_arm_sem); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | #ifdef CONFIG_PM
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static int op_arm_suspend(struct sys_device *dev, pm_message_t state) | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	down(&op_arm_sem); | 
					
						
							|  |  |  | 	if (op_arm_enabled) | 
					
						
							|  |  |  | 		op_arm_model->stop(); | 
					
						
							|  |  |  | 	up(&op_arm_sem); | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | static int op_arm_resume(struct sys_device *dev) | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	down(&op_arm_sem); | 
					
						
							|  |  |  | 	if (op_arm_enabled && op_arm_model->start()) | 
					
						
							|  |  |  | 		op_arm_enabled = 0; | 
					
						
							|  |  |  | 	up(&op_arm_sem); | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct sysdev_class oprofile_sysclass = { | 
					
						
							|  |  |  | 	set_kset_name("oprofile"), | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	.resume		= op_arm_resume, | 
					
						
							|  |  |  | 	.suspend	= op_arm_suspend, | 
					
						
							| 
									
										
										
										
											2005-10-28 14:51:15 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct sys_device device_oprofile = { | 
					
						
							|  |  |  | 	.id		= 0, | 
					
						
							|  |  |  | 	.cls		= &oprofile_sysclass, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init init_driverfs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(ret = sysdev_class_register(&oprofile_sysclass))) | 
					
						
							|  |  |  | 		ret = sysdev_register(&device_oprofile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void  exit_driverfs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	sysdev_unregister(&device_oprofile); | 
					
						
							|  |  |  | 	sysdev_class_unregister(&oprofile_sysclass); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define init_driverfs()	do { } while (0)
 | 
					
						
							|  |  |  | #define exit_driverfs() do { } while (0)
 | 
					
						
							|  |  |  | #endif /* CONFIG_PM */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:56:04 +01:00
										 |  |  | int __init oprofile_arch_init(struct oprofile_operations *ops) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 14:56:04 +01:00
										 |  |  | 	struct op_arm_model_spec *spec = NULL; | 
					
						
							|  |  |  | 	int ret = -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_CPU_XSCALE
 | 
					
						
							|  |  |  | 	spec = &op_xscale_spec; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (spec) { | 
					
						
							|  |  |  | 		init_MUTEX(&op_arm_sem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (spec->init() < 0) | 
					
						
							|  |  |  | 			return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		op_arm_model = spec; | 
					
						
							|  |  |  | 		init_driverfs(); | 
					
						
							|  |  |  | 		ops->create_files = op_arm_create_files; | 
					
						
							|  |  |  | 		ops->setup = op_arm_setup; | 
					
						
							|  |  |  | 		ops->shutdown = op_arm_stop; | 
					
						
							|  |  |  | 		ops->start = op_arm_start; | 
					
						
							|  |  |  | 		ops->stop = op_arm_stop; | 
					
						
							|  |  |  | 		ops->cpu_type = op_arm_model->name; | 
					
						
							|  |  |  | 		ops->backtrace = arm_backtrace; | 
					
						
							|  |  |  | 		printk(KERN_INFO "oprofile: using %s\n", spec->name); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:56:04 +01:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-28 14:56:04 +01:00
										 |  |  | void oprofile_arch_exit(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 	if (op_arm_model) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		exit_driverfs(); | 
					
						
							| 
									
										
										
										
											2005-10-28 14:54:21 +01:00
										 |  |  | 		op_arm_model = NULL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |