1 #include <linux/signal.h>
2 #include <linux/sched.h>
3 #include <linux/interrupt.h>
5 #include <linux/version.h>
6 #include <linux/vmalloc.h>
7 #include <linux/module.h>
8 #include <linux/delay.h>
9 #include <linux/init.h>
10 #include <linux/slab.h>
11 #include <linux/smp.h>
14 #include <asm/system.h>
15 #include <asm/uaccess.h>
17 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
18 #include <linux/wrapper.h>
20 #define NB_CPUS weight (phys_cpu_present_map)
25 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 4, 20)
26 #define iminor(inode) MINOR((inode)->i_rdev)
28 #define iminor(inode) minor((inode)->i_rdev)
31 #define NB_CPUS num_present_cpus ()
35 MODULE_DESCRIPTION ("Idle time collector");
37 static void (*idle_func
) (void);
38 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
39 MODULE_PARM (idle_func
, "l");
41 module_param (idle_func
, long, 0777);
43 MODULE_PARM_DESC (idle_func
, "address of default idle function");
46 static spinlock_t lock
= SPIN_LOCK_UNLOCKED
;
48 static void (*orig_pm_idle
) (void);
49 static unsigned int itc_major
;
50 static struct timeval total_idle_tv
[NR_CPUS
];
52 /**********************************************************************
56 **********************************************************************/
58 itc_open (struct inode
* inode
, struct file
* file
);
61 itc_release (struct inode
* inode
, struct file
* file
);
64 itc_ioctl (struct inode
* inode
, struct file
* file
,
65 unsigned int cmd
, unsigned long arg
);
68 itc_read (struct file
* file
, char * buf
, size_t count
, loff_t
* ppos
);
70 static struct file_operations itc_fops
=
74 .release
= itc_release
,
82 itc_release (struct inode
* inode
, struct file
* filp
)
88 itc_open (struct inode
* inode
, struct file
* filp
)
91 const struct file_operations
*old_fops
= filp
->f_op
;
92 unsigned int minor
= iminor (inode
);
97 /* old_fops = filp->f_op; */
98 filp
->f_op
= fops_get (&itc_fops
);
104 itc_read (struct file
*file
, char * buf
, size_t count
, loff_t
* ppos
)
107 size_t itemsize
= sizeof (total_idle_tv
[0]);
111 /* printk ("itemsize=%d cpus=%d count=%d\n", itemsize, NR_CPUS, count); */
112 if (count
< itemsize
* NB_CPUS
)
114 printk (KERN_ERR
"attempt to read something funny %d expected %d(%d,%d)\n",
115 count
, itemsize
* NB_CPUS
, itemsize
, NB_CPUS
);
119 spin_lock_irqsave (&lock
, flags
);
120 for (i
= 0; i
< NB_CPUS
; ++i
)
122 if (copy_to_user (buf
, &total_idle_tv
[i
], itemsize
))
124 printk (KERN_ERR
"failed to write %zu bytes to %p\n", itemsize
, buf
);
125 spin_unlock_irqrestore (&lock
, flags
);
132 spin_unlock_irqrestore (&lock
, flags
);
136 /**********************************************************************
140 **********************************************************************/
142 itc_ioctl (struct inode
* inode
, struct file
* filp
,
143 unsigned int cmd
, unsigned long arg
)
148 /**********************************************************************
152 **********************************************************************/
153 #if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 0)
158 void default_idle (void);
164 struct timeval tv1
, tv2
, tv3
, *t
;
168 spin_lock_irqsave (&lock
, flags
);
169 t
= &total_idle_tv
[smp_processor_id ()];
170 tv3
.tv_sec
= t
->tv_sec
;
171 tv3
.tv_usec
= t
->tv_usec
;
174 do_gettimeofday (&tv1
);
175 spin_unlock_irqrestore (&lock
, flags
);
204 spin_lock_irqsave (&lock
, flags
);
205 do_gettimeofday (&tv2
);
206 usec
= tv2
.tv_usec
- tv1
.tv_usec
+ tv3
.tv_usec
;
207 tv3
.tv_sec
+= (tv2
.tv_sec
- tv1
.tv_sec
);
208 while (usec
> 1000000)
214 t
->tv_sec
= tv3
.tv_sec
;
215 spin_unlock_irqrestore (&lock
, flags
);
218 /**********************************************************************
222 **********************************************************************/
229 if (!pm_idle
&& !idle_func
)
232 "itc: no idle function\n"
233 "itc: boot kernel with idle=halt option\n"
234 "itc: or specify idle_func (modprobe its idle_func=<address>\n");
239 err
= register_chrdev (itc_major
, DEVNAME
, &itc_fops
);
240 if (err
< 0 || ((itc_major
&& err
) || (!itc_major
&& !err
)))
242 printk (KERN_ERR
"itc: register_chrdev failed itc_major=%d err=%d\n",
254 "itc: driver successfully loaded pm_idle=%p default_idle=%p, idle_func=%p\n",
264 orig_pm_idle
= pm_idle
;
269 /**********************************************************************
273 **********************************************************************/
277 printk (KERN_DEBUG
"itc: unloading\n");
279 unregister_chrdev (itc_major
, DEVNAME
);
280 printk (KERN_DEBUG
"itc: unloaded\n");
282 pm_idle
= orig_pm_idle
;