Eh?
[apc.git] / mod3 / itc-mod.c
blob008784abb5da4fe7fc802986cdab96b198564d79
1 #include <linux/signal.h>
2 #include <linux/sched.h>
3 #include <linux/interrupt.h>
5 #include <linux/fs.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>
13 #include <linux/mm.h>
14 #include <linux/pm.h>
15 #include <linux/miscdevice.h>
16 #include <linux/kernel_stat.h>
17 #include <linux/cpuidle.h>
19 #include <asm/uaccess.h>
20 #include <asm/idle.h>
22 #if defined CONFIG_6xx || defined CONFIG_PPC64
23 #define ACCOUNT_IRQ
24 #endif
26 MODULE_DESCRIPTION ("Idle time collector");
27 MODULE_LICENSE ("GPL");
29 #define DEVNAME "itc"
31 #if LINUX_VERSION_CODE < KERNEL_VERSION (3, 0, 0)
32 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
33 #else
34 DEFINE_SPINLOCK (lock);
35 #endif
37 static unsigned int itc_major;
38 static atomic_t in_use;
40 struct itc
42 struct timeval cumm_sleep_time;
43 struct timeval sleep_started;
44 int sleeping;
47 static struct itc global_itc[NR_CPUS];
49 /**********************************************************************
51 * Utility functions
53 **********************************************************************/
54 static void
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;
60 if (usec < 0)
62 sec -= 1;
63 usec = 1000000 + usec;
65 c->tv_usec += usec;
66 if (c->tv_usec > 1000000)
68 c->tv_sec += sec + 1;
69 c->tv_usec -= 1000000;
71 else
73 c->tv_sec += sec;
77 static void
78 itc_monotonic (struct timeval *tv)
80 do_gettimeofday (tv);
83 #ifdef ACCOUNT_IRQ
84 static cputime64_t
85 itc_irq_time (void)
87 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
88 return cpustat->irq;
90 #endif
92 /**********************************************************************
94 * File operations
96 **********************************************************************/
97 static int
98 itc_open (struct inode * inode, struct file * file);
100 static int
101 itc_release (struct inode * inode, struct file * file);
103 static ssize_t
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,
109 .open = itc_open,
110 .release = itc_release,
111 .llseek = no_llseek,
112 .read = itc_read,
115 static struct miscdevice itc_misc_dev =
117 .minor = MISC_DYNAMIC_MINOR,
118 .name = "itc",
119 .fops = &itc_fops
123 static int idle_notification (struct notifier_block *nblk, unsigned long cmd,
124 void *y)
126 struct itc *itc;
127 struct timeval tv;
129 itc = &global_itc[smp_processor_id ()];
130 if (cmd == IDLE_START)
132 itc_monotonic (&itc->sleep_started);
133 itc->sleeping = 1;
135 else
137 itc_monotonic (&tv);
138 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
139 itc->sleeping = 0;
141 /* printk ("idle_notification %ld %p\n", cmd, y); */
142 return 0;
145 static struct notifier_block nblk =
147 .notifier_call = idle_notification
150 static int
151 itc_release (struct inode * inode, struct file * filp)
153 idle_notifier_unregister (&nblk);
154 atomic_set (&in_use, 0);
155 return 0;
158 static int
159 itc_open (struct inode * inode, struct file * filp)
161 int ret = 0;
162 unsigned int minor = iminor (inode);
164 if (itc_major)
166 if (minor != 0)
168 return -ENODEV;
172 if (atomic_cmpxchg (&in_use, 0, 1))
174 return -EALREADY;
177 filp->f_op = &itc_fops;
178 idle_notifier_register (&nblk);
180 return ret;
183 static ssize_t
184 itc_read (struct file *file, char * buf, size_t count, loff_t * ppos)
186 int i;
187 size_t itemsize = sizeof (global_itc[0].cumm_sleep_time);
188 ssize_t retval = 0;
189 unsigned long flags;
190 struct itc *itc = &global_itc[0];
191 struct timeval tmp[NR_CPUS], *tmpp;
193 tmpp = tmp;
194 if (count < itemsize * num_present_cpus ())
196 printk (KERN_ERR
197 "attempt to read something funny %zu expected %zu(%zu,%u)\n",
198 count, itemsize * num_present_cpus (),
199 itemsize, num_present_cpus ());
200 return -EINVAL;
203 spin_lock_irqsave (&lock, flags);
204 for (i = 0; i < NR_CPUS; ++i, ++itc)
206 if (cpu_present (i))
208 if (itc->sleeping)
210 struct timeval tv;
212 itc_monotonic (&tv);
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;
219 retval += itemsize;
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",
227 retval, buf);
228 retval = -EFAULT;
230 return retval;
233 /**********************************************************************
235 * Module constructor
237 **********************************************************************/
238 static __init int
239 init (void)
241 int err;
243 if (itc_major)
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",
249 itc_major, err);
250 return -ENODEV;
253 if (!itc_major)
255 itc_major = err;
258 else
260 err = misc_register (&itc_misc_dev);
261 if (err < 0)
263 printk (KERN_ERR "itc: misc_register failed err=%d\n", err);
264 return err;
268 return err;
271 /**********************************************************************
273 * Module destructor
275 **********************************************************************/
276 static __exit void
277 fini (void)
279 if (itc_major)
281 unregister_chrdev (itc_major, DEVNAME);
283 else
285 misc_deregister (&itc_misc_dev);
287 printk (KERN_DEBUG "itc: unloaded\n");
290 module_init (init);
291 module_exit (fini);