Small changes to make linux/tip happy
[apc.git] / mod / itc-mod.c
blob6a81958c1bdfe03495347b618c3e02deb147e11e
1 #ifdef CONFIG_PREEMPT_RT
2 #error Preempt RT kernels are not supported
3 #endif
5 #ifdef CONFIG_PREEMPT
6 #define ITC_PREEMPT_HACK
7 #endif
9 #include <linux/signal.h>
10 #include <linux/sched.h>
11 #include <linux/interrupt.h>
13 #include <linux/fs.h>
14 #include <linux/version.h>
15 #include <linux/vmalloc.h>
16 #include <linux/module.h>
17 #include <linux/delay.h>
18 #include <linux/init.h>
19 #include <linux/slab.h>
20 #include <linux/smp.h>
21 #include <linux/mm.h>
22 #include <linux/pm.h>
23 #include <linux/miscdevice.h>
24 #include <linux/kernel_stat.h>
25 #include <linux/smp_lock.h>
27 #include <asm/system.h>
28 #include <asm/uaccess.h>
30 #if defined CONFIG_6xx || defined CONFIG_PPC64
31 #include <asm/machdep.h>
32 #define pm_idle ppc_md.power_save
33 #define ACCOUNT_IRQ
34 #endif
36 #if !(defined CONFIG_X86 || defined CONFIG_6xx || defined CONFIG_PPC64)
37 #error Support for this architecture is nto written yet
38 #endif
40 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
41 #include <linux/wrapper.h>
42 #include <linux/smp_lock.h>
43 #ifdef CONFIG_SMP
44 #error Support for SMP on 2.4 series of kernels is not written yet
45 #else
46 #define num_present_cpus() 1
47 #define num_online_cpus() 1
48 /* #define cpu_online(n) 1 */
49 #define cpu_present(n) 1
50 #endif
52 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 4, 20)
53 #define iminor(inode) MINOR((inode)->i_rdev)
54 #else
55 #define iminor(inode) minor((inode)->i_rdev)
56 #endif
57 #endif
59 #ifdef CONFIG_PREEMPT
60 #define itc_enter_bkl() do { \
61 preempt_disable (); \
62 lock_kernel (); \
63 } while (0)
64 #define itc_leave_bkl() do { \
65 unlock_kernel (); \
66 preempt_enable (); \
67 } while (0)
68 #else
69 #define itc_enter_bkl lock_kernel
70 #define itc_leave_bkl unlock_kernel
71 #ifdef ITC_PREEMPT_HACK
72 #error Attempt to enable ITC_PREEMPT_HACK on non preemptible kernel
73 #endif
74 #endif
76 MODULE_DESCRIPTION ("Idle time collector");
78 #ifdef CONFIG_X86
79 static void (*fidle_func) (void);
80 static long idle_func;
81 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
82 MODULE_PARM (idle_func, "l");
83 #else
84 module_param (idle_func, long, 0644);
85 #endif
86 MODULE_PARM_DESC (idle_func, "address of default idle function");
87 #endif
89 #define DEVNAME "itc"
90 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
92 static void (*orig_pm_idle) (void);
93 static unsigned int itc_major;
95 struct itc
97 struct timeval cumm_sleep_time;
98 struct timeval sleep_started;
99 int sleeping;
102 static int in_use;
103 static struct itc global_itc[NR_CPUS];
105 /**********************************************************************
107 * Utility functions
109 **********************************************************************/
110 static void
111 cpeamb (struct timeval *c, struct timeval *a, struct timeval *b)
113 __typeof (c->tv_sec) sec = a->tv_sec - b->tv_sec;
114 __typeof (c->tv_usec) usec = a->tv_usec - b->tv_usec;
116 if (usec < 0)
118 sec -= 1;
119 usec = 1000000 + usec;
121 c->tv_usec += usec;
122 if (c->tv_usec > 1000000)
124 c->tv_sec += sec + 1;
125 c->tv_usec -= 1000000;
127 else
129 c->tv_sec += sec;
133 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
134 /* XXX: 2.4 */
135 /**********************************************************************
137 * Dummy to make sure we are unloaded properly
139 **********************************************************************/
140 static void
141 dummy_wakeup (void *unused)
143 printk (KERN_DEBUG "waking up %d\n", smp_processor_id ());
144 /* needed? safe? */
145 set_need_resched ();
147 #endif
149 /**********************************************************************
151 * idle
153 **********************************************************************/
154 #if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 0)
155 #define QUIRK
156 #else
157 void default_idle (void);
158 #endif
160 static void
161 itc_monotonic (struct timeval *tv)
163 do_gettimeofday (tv);
166 #ifdef ACCOUNT_IRQ
167 static cputime64_t
168 itc_irq_time (void)
170 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
171 return cpustat->irq;
173 #endif
175 static void
176 itc_idle (void)
178 struct itc *itc;
179 struct timeval tv;
180 unsigned long flags;
181 #ifdef ACCOUNT_IRQ
182 struct timeval tv_irq_before, tv_irq_after;
183 cputime64_t irq_time_before, irq_time_after;
184 #endif
186 #ifdef ITC_PREEMPT_HACK
187 preempt_disable ();
188 #endif
190 /* printk ("idle in %d\n", smp_processor_id ()); */
191 spin_lock_irqsave (&lock, flags);
192 itc = &global_itc[smp_processor_id ()];
193 itc_monotonic (&itc->sleep_started);
194 itc->sleeping = 1;
195 #ifdef ACCOUNT_IRQ
196 irq_time_before = itc_irq_time ();
197 #endif
198 spin_unlock_irqrestore (&lock, flags);
200 #ifdef QUIRK
201 if (orig_pm_idle)
203 orig_pm_idle ();
205 #ifdef CONFIG_X86
206 else
208 fidle_func ();
210 #endif
211 #else
212 if (orig_pm_idle)
214 orig_pm_idle ();
216 else
218 #ifdef CONFIG_X86
219 if (fidle_func)
221 fidle_func ();
223 else
224 #endif
226 default_idle ();
229 #endif
231 spin_lock_irqsave (&lock, flags);
232 itc_monotonic (&tv);
234 #ifdef ACCOUNT_IRQ
235 irq_time_after = itc_irq_time ();
237 cputime_to_timeval (irq_time_before, &tv_irq_before);
238 cputime_to_timeval (irq_time_after, &tv_irq_after);
240 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
241 cpeamb (&itc->cumm_sleep_time, &tv_irq_before, &tv_irq_after);
242 #else
243 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
244 #endif
246 itc->sleeping = 0;
247 spin_unlock_irqrestore (&lock, flags);
248 /* printk ("idle out %d\n", smp_processor_id ()); */
250 #ifdef ITC_PREEMPT_HACK
251 preempt_enable ();
252 #endif
255 /**********************************************************************
257 * File operations
259 **********************************************************************/
260 static int
261 itc_open (struct inode * inode, struct file * file);
263 static int
264 itc_release (struct inode * inode, struct file * file);
266 static int
267 itc_ioctl (struct inode * inode, struct file * file,
268 unsigned int cmd, unsigned long arg);
270 static ssize_t
271 itc_read (struct file * file, char * buf, size_t count, loff_t * ppos);
273 static struct file_operations itc_fops =
275 .owner = THIS_MODULE,
276 .open = itc_open,
277 .release = itc_release,
278 .ioctl = itc_ioctl,
279 .llseek = no_llseek,
280 .read = itc_read,
283 static struct miscdevice itc_misc_dev =
285 .minor = MISC_DYNAMIC_MINOR,
286 .name = "itc",
287 .fops = &itc_fops
290 static int
291 itc_release (struct inode * inode, struct file * filp)
293 itc_enter_bkl ();
294 pm_idle = orig_pm_idle;
295 in_use = 0;
296 itc_leave_bkl ();
297 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
298 /* XXX: 2.4 */
299 #if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 26)
300 /* 15c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0d */
301 on_each_cpu (dummy_wakeup, NULL, 1);
302 #else
303 on_each_cpu (dummy_wakeup, NULL, 0, 1);
304 #endif
305 #endif
306 return 0;
309 static int
310 itc_open (struct inode * inode, struct file * filp)
312 int ret = 0;
313 const struct file_operations *old_fops = filp->f_op;
314 unsigned int minor = iminor (inode);
316 if (itc_major)
318 if (minor != 0)
320 return -ENODEV;
324 if (in_use)
326 return -EALREADY;
329 /* old_fops = filp->f_op; */
330 filp->f_op = fops_get (&itc_fops);
331 fops_put (old_fops);
333 itc_enter_bkl ();
334 if (pm_idle != itc_idle)
336 orig_pm_idle = pm_idle;
338 pm_idle = itc_idle;
339 in_use = 1;
340 itc_leave_bkl ();
342 return ret;
345 static ssize_t
346 itc_read (struct file *file, char * buf, size_t count, loff_t * ppos)
348 int i;
349 size_t itemsize = sizeof (global_itc[0].cumm_sleep_time);
350 ssize_t retval = 0;
351 unsigned long flags;
352 struct itc *itc = &global_itc[0];
353 struct timeval tmp[NR_CPUS], *tmpp;
355 tmpp = tmp;
356 if (count < itemsize * num_present_cpus ())
358 printk (KERN_ERR
359 "attempt to read something funny %zu expected %zu(%zu,%u)\n",
360 count, itemsize * num_present_cpus (),
361 itemsize, num_present_cpus ());
362 return -EINVAL;
365 spin_lock_irqsave (&lock, flags);
366 for (i = 0; i < NR_CPUS; ++i, ++itc)
368 if (cpu_present (i))
370 if (itc->sleeping)
372 struct timeval tv;
374 itc_monotonic (&tv);
375 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
376 itc->sleep_started.tv_sec = tv.tv_sec;
377 itc->sleep_started.tv_usec = tv.tv_usec;
380 *tmpp++ = itc->cumm_sleep_time;
381 retval += itemsize;
384 spin_unlock_irqrestore (&lock, flags);
386 if (copy_to_user (buf, tmp, retval))
388 printk (KERN_ERR "failed to write %zu bytes to %p\n",
389 retval, buf);
390 retval = -EFAULT;
392 return retval;
395 /**********************************************************************
397 * ioctl handler
399 **********************************************************************/
400 static int
401 itc_ioctl (struct inode * inode, struct file * filp,
402 unsigned int cmd, unsigned long arg)
404 return -EINVAL;
407 /**********************************************************************
409 * Module constructor
411 **********************************************************************/
412 static __init int
413 init (void)
415 int err;
417 #ifdef CONFIG_X86
418 fidle_func = (void (*) (void)) idle_func;
419 #endif
421 #ifdef QUIRK
422 if (!pm_idle
423 #ifdef CONFIG_X86
424 && !fidle_func
425 #endif
428 printk
429 (KERN_ERR
430 "itc: no idle function\n"
431 "itc: boot kernel with idle=halt option\n"
432 "itc: or specify idle_func (modprobe itc idle_func=<address>)\n");
433 return -ENODEV;
435 #endif
437 if (itc_major)
439 err = register_chrdev (itc_major, DEVNAME, &itc_fops);
440 if (err < 0 || ((itc_major && err) || (!itc_major && !err)))
442 printk (KERN_ERR "itc: register_chrdev failed itc_major=%d err=%d\n",
443 itc_major, err);
444 return -ENODEV;
447 if (!itc_major)
449 itc_major = err;
452 else
454 err = misc_register (&itc_misc_dev);
455 if (err < 0)
457 printk (KERN_ERR "itc: misc_register failed err=%d\n", err);
458 return err;
462 orig_pm_idle = pm_idle;
463 printk
464 (KERN_DEBUG
465 "itc: driver loaded pm_idle=%p default_idle=%p"
466 #ifdef CONFIG_X86
467 ", idle_func=%p"
468 #endif
469 "\n",
470 pm_idle
471 #ifdef QUIRK
472 , NULL
473 #else
474 , default_idle
475 #endif
476 #ifdef CONFIG_X86
477 , fidle_func
478 #endif
480 printk (KERN_DEBUG "itc: CPUs(%d present=%d online=%d)"
481 #ifdef QUIRK
482 " Q"
483 #endif
484 #ifdef CONFIG_APM
485 " A"
486 #endif
487 #ifdef CONFIG_SMP
488 " S"
489 #endif
490 #ifdef CONFIG_PREEMPT
491 " P"
492 #endif
493 "\n",
494 NR_CPUS, num_present_cpus (), num_online_cpus ());
495 return 0;
498 /**********************************************************************
500 * Module destructor
502 **********************************************************************/
503 static __exit void
504 fini (void)
506 printk (KERN_DEBUG "itc: unloading (resetting pm_idle to %p)\n",
507 orig_pm_idle);
508 if (itc_major)
510 unregister_chrdev (itc_major, DEVNAME);
512 else
514 misc_deregister (&itc_misc_dev);
516 printk (KERN_DEBUG "itc: unloaded\n");
519 module_init (init);
520 module_exit (fini);