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 dummy_wakeup (void *unused
)
164 itc_open (struct inode
* inode
, struct file
* filp
)
167 unsigned int minor
= iminor (inode
);
177 if (atomic_cmpxchg (&in_use
, 0, 1))
182 filp
->f_op
= &itc_fops
;
183 idle_notifier_register (&nblk
);
184 on_each_cpu (dummy_wakeup
, NULL
, 1);
190 itc_read (struct file
*file
, char * buf
, size_t count
, loff_t
* ppos
)
193 size_t itemsize
= sizeof (global_itc
[0].cumm_sleep_time
);
196 struct itc
*itc
= &global_itc
[0];
197 struct timeval tmp
[NR_CPUS
], *tmpp
;
200 if (count
< itemsize
* num_present_cpus ())
203 "attempt to read something funny %zu expected %zu(%zu,%u)\n",
204 count
, itemsize
* num_present_cpus (),
205 itemsize
, num_present_cpus ());
209 spin_lock_irqsave (&lock
, flags
);
210 for (i
= 0; i
< NR_CPUS
; ++i
, ++itc
)
219 cpeamb (&itc
->cumm_sleep_time
, &tv
, &itc
->sleep_started
);
220 itc
->sleep_started
.tv_sec
= tv
.tv_sec
;
221 itc
->sleep_started
.tv_usec
= tv
.tv_usec
;
224 *tmpp
++ = itc
->cumm_sleep_time
;
228 spin_unlock_irqrestore (&lock
, flags
);
230 if (copy_to_user (buf
, tmp
, retval
))
232 printk (KERN_ERR
"failed to write %zu bytes to %p\n",
239 /**********************************************************************
243 **********************************************************************/
251 err
= register_chrdev (itc_major
, DEVNAME
, &itc_fops
);
252 if (err
< 0 || ((itc_major
&& err
) || (!itc_major
&& !err
)))
254 printk (KERN_ERR
"itc: register_chrdev failed itc_major=%d err=%d\n",
266 err
= misc_register (&itc_misc_dev
);
269 printk (KERN_ERR
"itc: misc_register failed err=%d\n", err
);
277 /**********************************************************************
281 **********************************************************************/
287 unregister_chrdev (itc_major
, DEVNAME
);
291 misc_deregister (&itc_misc_dev
);
293 printk (KERN_DEBUG
"itc: unloaded\n");