1 #include <linux/signal.h>
2 #include <linux/sched.h>
3 #include <linux/interrupt.h>
6 #include <linux/version.h>
7 #include <linux/vmalloc.h>
8 #include <linux/module.h>
9 #include <linux/delay.h>
10 #include <linux/init.h>
11 #include <linux/slab.h>
12 #include <linux/smp.h>
15 #include <linux/miscdevice.h>
16 #include <linux/kernel_stat.h>
17 #include <linux/cpuidle.h>
19 #include <asm/uaccess.h>
22 #if defined CONFIG_6xx || defined CONFIG_PPC64
26 MODULE_DESCRIPTION ("Idle time collector");
27 MODULE_LICENSE ("GPL");
31 #if LINUX_VERSION_CODE < KERNEL_VERSION (3, 0, 0)
32 static spinlock_t lock
= SPIN_LOCK_UNLOCKED
;
34 DEFINE_SPINLOCK (lock
);
37 static unsigned int itc_major
;
38 static atomic_t in_use
;
42 struct timeval cumm_sleep_time
;
43 struct timeval sleep_started
;
47 static struct itc global_itc
[NR_CPUS
];
49 /**********************************************************************
53 **********************************************************************/
55 cpeamb (struct timeval
*c
, struct timeval
*a
, struct timeval
*b
)
57 __typeof (c
->tv_sec
) sec
= a
->tv_sec
- b
->tv_sec
;
58 __typeof (c
->tv_usec
) usec
= a
->tv_usec
- b
->tv_usec
;
63 usec
= 1000000 + usec
;
66 if (c
->tv_usec
> 1000000)
69 c
->tv_usec
-= 1000000;
78 itc_monotonic (struct timeval
*tv
)
87 struct cpu_usage_stat
*cpustat
= &kstat_this_cpu
.cpustat
;
92 /**********************************************************************
96 **********************************************************************/
98 itc_open (struct inode
* inode
, struct file
* file
);
101 itc_release (struct inode
* inode
, struct file
* file
);
104 itc_read (struct file
* file
, char * buf
, size_t count
, loff_t
* ppos
);
106 static struct file_operations itc_fops
=
108 .owner
= THIS_MODULE
,
110 .release
= itc_release
,
115 static struct miscdevice itc_misc_dev
=
117 .minor
= MISC_DYNAMIC_MINOR
,
123 static int idle_notification (struct notifier_block
*nblk
, unsigned long cmd
,
129 itc
= &global_itc
[smp_processor_id ()];
130 if (cmd
== IDLE_START
)
132 itc_monotonic (&itc
->sleep_started
);
138 cpeamb (&itc
->cumm_sleep_time
, &tv
, &itc
->sleep_started
);
141 /* printk ("idle_notification %ld %p\n", cmd, y); */
145 static struct notifier_block nblk
=
147 .notifier_call
= idle_notification
151 itc_release (struct inode
* inode
, struct file
* filp
)
153 idle_notifier_unregister (&nblk
);
154 atomic_set (&in_use
, 0);
159 itc_open (struct inode
* inode
, struct file
* filp
)
162 unsigned int minor
= iminor (inode
);
172 if (atomic_cmpxchg (&in_use
, 0, 1))
177 filp
->f_op
= &itc_fops
;
178 idle_notifier_register (&nblk
);
184 itc_read (struct file
*file
, char * buf
, size_t count
, loff_t
* ppos
)
187 size_t itemsize
= sizeof (global_itc
[0].cumm_sleep_time
);
190 struct itc
*itc
= &global_itc
[0];
191 struct timeval tmp
[NR_CPUS
], *tmpp
;
194 if (count
< itemsize
* num_present_cpus ())
197 "attempt to read something funny %zu expected %zu(%zu,%u)\n",
198 count
, itemsize
* num_present_cpus (),
199 itemsize
, num_present_cpus ());
203 spin_lock_irqsave (&lock
, flags
);
204 for (i
= 0; i
< NR_CPUS
; ++i
, ++itc
)
213 cpeamb (&itc
->cumm_sleep_time
, &tv
, &itc
->sleep_started
);
214 itc
->sleep_started
.tv_sec
= tv
.tv_sec
;
215 itc
->sleep_started
.tv_usec
= tv
.tv_usec
;
218 *tmpp
++ = itc
->cumm_sleep_time
;
222 spin_unlock_irqrestore (&lock
, flags
);
224 if (copy_to_user (buf
, tmp
, retval
))
226 printk (KERN_ERR
"failed to write %zu bytes to %p\n",
233 /**********************************************************************
237 **********************************************************************/
245 err
= register_chrdev (itc_major
, DEVNAME
, &itc_fops
);
246 if (err
< 0 || ((itc_major
&& err
) || (!itc_major
&& !err
)))
248 printk (KERN_ERR
"itc: register_chrdev failed itc_major=%d err=%d\n",
260 err
= misc_register (&itc_misc_dev
);
263 printk (KERN_ERR
"itc: misc_register failed err=%d\n", err
);
271 /**********************************************************************
275 **********************************************************************/
281 unregister_chrdev (itc_major
, DEVNAME
);
285 misc_deregister (&itc_misc_dev
);
287 printk (KERN_DEBUG
"itc: unloaded\n");