|
Packit |
577717 |
/* $Id: init.c,v 1.68.2.5 2009/01/23 17:21:20 mikpe Exp $
|
|
Packit |
577717 |
* Performance-monitoring counters driver.
|
|
Packit |
577717 |
* Top-level initialisation code.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (C) 1999-2007, 2009 Mikael Pettersson
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <linux/version.h>
|
|
Packit |
577717 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
|
Packit |
577717 |
#include <linux/config.h>
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
#include <linux/module.h>
|
|
Packit |
577717 |
#include <linux/fs.h>
|
|
Packit |
577717 |
#include <linux/init.h>
|
|
Packit |
577717 |
#include <linux/miscdevice.h>
|
|
Packit |
577717 |
#include <linux/sched.h>
|
|
Packit |
577717 |
#include <linux/perfctr.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include <asm/uaccess.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "compat.h"
|
|
Packit |
577717 |
#include "virtual.h"
|
|
Packit |
577717 |
#include "global.h"
|
|
Packit |
577717 |
#include "version.h"
|
|
Packit |
577717 |
#include "marshal.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
MODULE_AUTHOR("Mikael Pettersson <mikpe@it.uu.se>");
|
|
Packit |
577717 |
MODULE_DESCRIPTION("Performance-monitoring counters driver");
|
|
Packit |
577717 |
MODULE_LICENSE("GPL");
|
|
Packit |
577717 |
MODULE_ALIAS("char-major-10-182");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef CONFIG_PERFCTR_DEBUG
|
|
Packit |
577717 |
#define VERSION_DEBUG " DEBUG"
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
#define VERSION_DEBUG
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
struct perfctr_info perfctr_info = {
|
|
Packit |
577717 |
.abi_version = PERFCTR_ABI_VERSION,
|
|
Packit |
577717 |
.driver_version = VERSION VERSION_DEBUG,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
char *perfctr_cpu_name __initdata;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int sys_perfctr_abi(unsigned int *argp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if( put_user(PERFCTR_ABI_VERSION, argp) )
|
|
Packit |
577717 |
return -EFAULT;
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int sys_perfctr_info(struct perfctr_struct_buf *argp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return perfctr_copy_to_user(argp, &perfctr_info, &perfctr_info_sdesc);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int cpus_copy_to_user(const cpumask_t *cpus, struct perfctr_cpu_mask *argp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
const unsigned int k_nrwords = PERFCTR_CPUMASK_NRLONGS*(sizeof(long)/sizeof(int));
|
|
Packit |
577717 |
unsigned int u_nrwords;
|
|
Packit |
577717 |
unsigned int ui, ki, j;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if( get_user(u_nrwords, &argp->nrwords) )
|
|
Packit |
577717 |
return -EFAULT;
|
|
Packit |
577717 |
if( put_user(k_nrwords, &argp->nrwords) )
|
|
Packit |
577717 |
return -EFAULT;
|
|
Packit |
577717 |
if( u_nrwords < k_nrwords )
|
|
Packit |
577717 |
return -EOVERFLOW;
|
|
Packit |
577717 |
for(ui = 0, ki = 0; ki < PERFCTR_CPUMASK_NRLONGS; ++ki) {
|
|
Packit |
577717 |
unsigned long mask = cpus_addr(*cpus)[ki];
|
|
Packit |
577717 |
for(j = 0; j < sizeof(long)/sizeof(int); ++j) {
|
|
Packit |
577717 |
if( put_user((unsigned int)mask, &argp->mask[ui]) )
|
|
Packit |
577717 |
return -EFAULT;
|
|
Packit |
577717 |
++ui;
|
|
Packit |
577717 |
mask = (mask >> (8*sizeof(int)-1)) >> 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int sys_perfctr_cpus(struct perfctr_cpu_mask *argp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
cpumask_t cpus = cpu_online_map;
|
|
Packit |
577717 |
return cpus_copy_to_user(&cpus, argp);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int sys_perfctr_cpus_forbidden(struct perfctr_cpu_mask *argp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
cpumask_t cpus = perfctr_cpus_forbidden_mask;
|
|
Packit |
577717 |
return cpus_copy_to_user(&cpus, argp);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if defined(CONFIG_IA32_EMULATION) && !HAVE_COMPAT_IOCTL
|
|
Packit |
577717 |
#include <asm/ioctl32.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __init perfctr_register_ioctl32_conversions(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int err;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
err = register_ioctl32_conversion(PERFCTR_ABI, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(PERFCTR_INFO, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(PERFCTR_CPUS, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(PERFCTR_CPUS_FORBIDDEN, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_CREAT, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_OPEN, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_READ_SUM, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_UNLINK, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_CONTROL, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_IRESUME, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(VPERFCTR_READ_CONTROL, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(GPERFCTR_CONTROL, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(GPERFCTR_READ, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(GPERFCTR_STOP, 0);
|
|
Packit |
577717 |
err |= register_ioctl32_conversion(GPERFCTR_START, 0);
|
|
Packit |
577717 |
if( err )
|
|
Packit |
577717 |
printk(KERN_ERR "perfctr: register_ioctl32_conversion() failed\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void __exit perfctr_unregister_ioctl32_conversions(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unregister_ioctl32_conversion(PERFCTR_ABI);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(PERFCTR_INFO);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(PERFCTR_CPUS);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(PERFCTR_CPUS_FORBIDDEN);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_CREAT);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_OPEN);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_READ_SUM);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_UNLINK);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_CONTROL);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_IRESUME);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(VPERFCTR_READ_CONTROL);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(GPERFCTR_CONTROL);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(GPERFCTR_READ);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(GPERFCTR_STOP);
|
|
Packit |
577717 |
unregister_ioctl32_conversion(GPERFCTR_START);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
#define perfctr_register_ioctl32_conversions() do{}while(0)
|
|
Packit |
577717 |
#define perfctr_unregister_ioctl32_conversions() do{}while(0)
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static long dev_perfctr_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
switch( cmd ) {
|
|
Packit |
577717 |
case PERFCTR_ABI:
|
|
Packit |
577717 |
return sys_perfctr_abi((unsigned int*)arg);
|
|
Packit |
577717 |
case PERFCTR_INFO:
|
|
Packit |
577717 |
return sys_perfctr_info((struct perfctr_struct_buf*)arg);
|
|
Packit |
577717 |
case PERFCTR_CPUS:
|
|
Packit |
577717 |
return sys_perfctr_cpus((struct perfctr_cpu_mask*)arg);
|
|
Packit |
577717 |
case PERFCTR_CPUS_FORBIDDEN:
|
|
Packit |
577717 |
return sys_perfctr_cpus_forbidden((struct perfctr_cpu_mask*)arg);
|
|
Packit |
577717 |
case VPERFCTR_CREAT:
|
|
Packit |
577717 |
return vperfctr_attach((int)arg, 1);
|
|
Packit |
577717 |
case VPERFCTR_OPEN:
|
|
Packit |
577717 |
return vperfctr_attach((int)arg, 0);
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return gperfctr_ioctl(filp, cmd, arg);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return -EINVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#if !HAVE_UNLOCKED_IOCTL
|
|
Packit |
577717 |
static int dev_perfctr_ioctl_oldstyle(struct inode *inode, struct file *filp,
|
|
Packit |
577717 |
unsigned int cmd, unsigned long arg)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return dev_perfctr_ioctl(filp, cmd, arg);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct file_operations dev_perfctr_file_ops = {
|
|
Packit |
577717 |
.owner = THIS_MODULE,
|
|
Packit |
577717 |
/* 2.6.11-rc2 introduced HAVE_UNLOCKED_IOCTL and HAVE_COMPAT_IOCTL */
|
|
Packit |
577717 |
#if HAVE_UNLOCKED_IOCTL
|
|
Packit |
577717 |
.unlocked_ioctl = dev_perfctr_ioctl,
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
.ioctl = dev_perfctr_ioctl_oldstyle,
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
#if defined(CONFIG_IA32_EMULATION) && HAVE_COMPAT_IOCTL
|
|
Packit |
577717 |
.compat_ioctl = dev_perfctr_ioctl,
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static struct miscdevice dev_perfctr = {
|
|
Packit |
577717 |
.minor = 182,
|
|
Packit |
577717 |
.name = "perfctr",
|
|
Packit |
577717 |
.fops = &dev_perfctr_file_ops,
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
int __init perfctr_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int err;
|
|
Packit |
577717 |
if( (err = perfctr_cpu_init()) != 0 ) {
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr: not supported by this processor\n");
|
|
Packit |
577717 |
return err;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if( (err = vperfctr_init()) != 0 )
|
|
Packit |
577717 |
return err;
|
|
Packit |
577717 |
gperfctr_init();
|
|
Packit |
577717 |
if( (err = misc_register(&dev_perfctr)) != 0 ) {
|
|
Packit |
577717 |
printk(KERN_ERR "/dev/perfctr: failed to register, errno %d\n",
|
|
Packit |
577717 |
-err);
|
|
Packit |
577717 |
return err;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
perfctr_register_ioctl32_conversions();
|
|
Packit |
577717 |
printk(KERN_INFO "perfctr: driver %s, cpu type %s at %u kHz\n",
|
|
Packit |
577717 |
perfctr_info.driver_version,
|
|
Packit |
577717 |
perfctr_cpu_name,
|
|
Packit |
577717 |
perfctr_info.cpu_khz);
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
void __exit perfctr_exit(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
perfctr_unregister_ioctl32_conversions();
|
|
Packit |
577717 |
misc_deregister(&dev_perfctr);
|
|
Packit |
577717 |
vperfctr_exit();
|
|
Packit |
577717 |
perfctr_cpu_exit();
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
module_init(perfctr_init)
|
|
Packit |
577717 |
module_exit(perfctr_exit)
|