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>
15 #include <asm/system.h>
16 #include <asm/uaccess.h>
19 #include <asm/machdep.h>
20 #define pm_idle ppc_md.power_save
23 #if !(defined CONFIG_X86 || defined CONFIG_6xx)
24 #error Support for this architecture is not written yet
27 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
28 #include <linux/wrapper.h>
30 #define NB_CPUS weight (phys_cpu_present_map)
35 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 4, 20)
36 #define iminor(inode) MINOR((inode)->i_rdev)
38 #define iminor(inode) minor((inode)->i_rdev)
41 #define NB_CPUS num_present_cpus ()
45 MODULE_DESCRIPTION ("Idle time collector");
47 static void (*idle_func
) (void);
50 /* there are many ways to prevent gcc from complaining about module_param
51 and function pointer vs long, but let's not */
52 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
53 MODULE_PARM (idle_func
, "l");
55 module_param (idle_func
, long, 0777);
57 MODULE_PARM_DESC (idle_func
, "address of default idle function");
61 static spinlock_t lock
= SPIN_LOCK_UNLOCKED
;
63 static void (*orig_pm_idle
) (void);
64 static unsigned int itc_major
;
68 struct timeval cumm_sleep_time
;
69 struct timeval sleep_started
;
73 static struct itc global_itc
[NR_CPUS
];
75 /**********************************************************************
79 **********************************************************************/
81 cpeamb (struct timeval
*c
, struct timeval
*a
, struct timeval
*b
)
83 __typeof (c
->tv_sec
) sec
= a
->tv_sec
- b
->tv_sec
;
84 __typeof (c
->tv_usec
) usec
= a
->tv_usec
- b
->tv_usec
;
89 usec
= 1000000 + usec
;
92 if (c
->tv_usec
> 1000000)
95 c
->tv_usec
-= 1000000;
103 /**********************************************************************
107 **********************************************************************/
109 itc_open (struct inode
* inode
, struct file
* file
);
112 itc_release (struct inode
* inode
, struct file
* file
);
115 itc_ioctl (struct inode
* inode
, struct file
* file
,
116 unsigned int cmd
, unsigned long arg
);
119 itc_read (struct file
* file
, char * buf
, size_t count
, loff_t
* ppos
);
121 static struct file_operations itc_fops
=
123 .owner
= THIS_MODULE
,
125 .release
= itc_release
,
133 itc_release (struct inode
* inode
, struct file
* filp
)
139 itc_open (struct inode
* inode
, struct file
* filp
)
142 const struct file_operations
*old_fops
= filp
->f_op
;
143 unsigned int minor
= iminor (inode
);
148 /* old_fops = filp->f_op; */
149 filp
->f_op
= fops_get (&itc_fops
);
155 itc_read (struct file
*file
, char * buf
, size_t count
, loff_t
* ppos
)
158 size_t itemsize
= sizeof (global_itc
[0].cumm_sleep_time
);
161 struct itc
*itc
= &global_itc
[0];
163 /* printk ("itemsize=%d cpus=%d count=%d\n", itemsize, NR_CPUS, count); */
164 if (count
< itemsize
* NB_CPUS
)
167 "attempt to read something funny %d expected %d(%d,%d)\n",
168 count
, itemsize
* NB_CPUS
, itemsize
, NB_CPUS
);
172 spin_lock_irqsave (&lock
, flags
);
173 for (i
= 0; i
< NB_CPUS
; ++i
, ++itc
)
179 do_gettimeofday (&tv
);
180 cpeamb (&itc
->cumm_sleep_time
, &tv
, &itc
->sleep_started
);
181 itc
->sleep_started
.tv_sec
= tv
.tv_sec
;
182 itc
->sleep_started
.tv_usec
= tv
.tv_usec
;
185 if (copy_to_user (buf
, &itc
->cumm_sleep_time
, itemsize
))
187 printk (KERN_ERR
"failed to write %zu bytes to %p\n", itemsize
, buf
);
195 spin_unlock_irqrestore (&lock
, flags
);
199 /**********************************************************************
203 **********************************************************************/
205 itc_ioctl (struct inode
* inode
, struct file
* filp
,
206 unsigned int cmd
, unsigned long arg
)
211 /**********************************************************************
215 **********************************************************************/
216 #if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 0)
221 void default_idle (void);
231 /* printk ("idle in\n"); */
232 spin_lock_irqsave (&lock
, flags
);
233 itc
= &global_itc
[smp_processor_id ()];
234 do_gettimeofday (&itc
->sleep_started
);
235 spin_unlock_irqrestore (&lock
, flags
);
264 spin_lock_irqsave (&lock
, flags
);
265 do_gettimeofday (&tv
);
266 cpeamb (&itc
->cumm_sleep_time
, &tv
, &itc
->sleep_started
);
268 spin_unlock_irqrestore (&lock
, flags
);
269 /* printk ("idle out\n"); */
272 /**********************************************************************
276 **********************************************************************/
283 if (!pm_idle
&& !idle_func
)
287 "itc: no idle function\n"
288 "itc: boot kernel with idle=halt option\n"
289 "itc: or specify idle_func (modprobe itc idle_func=<address>)\n");
294 err
= register_chrdev (itc_major
, DEVNAME
, &itc_fops
);
295 if (err
< 0 || ((itc_major
&& err
) || (!itc_major
&& !err
)))
297 printk (KERN_ERR
"itc: register_chrdev failed itc_major=%d err=%d\n",
309 "itc: driver loaded pm_idle=%p default_idle=%p, idle_func=%p\n",
319 orig_pm_idle
= pm_idle
;
324 /**********************************************************************
328 **********************************************************************/
332 printk (KERN_DEBUG
"itc: unloading\n");
334 unregister_chrdev (itc_major
, DEVNAME
);
335 printk (KERN_DEBUG
"itc: unloaded\n");
337 pm_idle
= orig_pm_idle
;