Link against user32
[apc.git] / mod / itc-mod.c
blob480361355ac98a493f33a4c969cbaa2e6ae05e43
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>
26 #include <asm/system.h>
27 #include <asm/uaccess.h>
29 #if defined CONFIG_6xx || defined CONFIG_PPC64
30 #include <asm/machdep.h>
31 #define pm_idle ppc_md.power_save
32 #define ACCOUNT_IRQ
33 #endif
35 #if !(defined CONFIG_X86 || defined CONFIG_6xx || defined CONFIG_PPC64)
36 #error Support for this architecture is nto written yet
37 #endif
39 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
40 #include <linux/wrapper.h>
41 #include <linux/smp_lock.h>
42 #ifdef CONFIG_SMP
43 #error Support for SMP on 2.4 series of kernels is not written yet
44 #else
45 #define num_present_cpus() 1
46 #define num_online_cpus() 1
47 /* #define cpu_online(n) 1 */
48 #define cpu_present(n) 1
49 #endif
51 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 4, 20)
52 #define iminor(inode) MINOR((inode)->i_rdev)
53 #else
54 #define iminor(inode) minor((inode)->i_rdev)
55 #endif
56 #endif
58 #ifdef CONFIG_PREEMPT
59 #define itc_enter_bkl() do { \
60 preempt_disable (); \
61 lock_kernel (); \
62 } while (0)
63 #define itc_leave_bkl() do { \
64 unlock_kernel (); \
65 preempt_enable (); \
66 } while (0)
67 #else
68 #define itc_enter_bkl lock_kernel
69 #define itc_leave_bkl unlock_kernel
70 #ifdef ITC_PREEMPT_HACK
71 #error Attempt to enable ITC_PREEMPT_HACK on non preemptible kernel
72 #endif
73 #endif
75 MODULE_DESCRIPTION ("Idle time collector");
77 #ifdef CONFIG_X86
78 static void (*fidle_func) (void);
79 static long idle_func;
80 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
81 MODULE_PARM (idle_func, "l");
82 #else
83 module_param (idle_func, long, 0644);
84 #endif
85 MODULE_PARM_DESC (idle_func, "address of default idle function");
86 #endif
88 #define DEVNAME "itc"
89 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
91 static void (*orig_pm_idle) (void);
92 static unsigned int itc_major;
94 struct itc
96 struct timeval cumm_sleep_time;
97 struct timeval sleep_started;
98 int sleeping;
101 static int in_use;
102 static struct itc global_itc[NR_CPUS];
104 /**********************************************************************
106 * Utility functions
108 **********************************************************************/
109 static void
110 cpeamb (struct timeval *c, struct timeval *a, struct timeval *b)
112 __typeof (c->tv_sec) sec = a->tv_sec - b->tv_sec;
113 __typeof (c->tv_usec) usec = a->tv_usec - b->tv_usec;
115 if (usec < 0)
117 sec -= 1;
118 usec = 1000000 + usec;
120 c->tv_usec += usec;
121 if (c->tv_usec > 1000000)
123 c->tv_sec += sec + 1;
124 c->tv_usec -= 1000000;
126 else
128 c->tv_sec += sec;
132 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
133 /* XXX: 2.4 */
134 /**********************************************************************
136 * Dummy to make sure we are unloaded properly
138 **********************************************************************/
139 static void
140 dummy_wakeup (void *unused)
142 printk (KERN_DEBUG "waking up %d\n", smp_processor_id ());
143 /* needed? safe? */
144 set_need_resched ();
146 #endif
148 /**********************************************************************
150 * idle
152 **********************************************************************/
153 #if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 0)
154 #define QUIRK
155 #else
156 void default_idle (void);
157 #endif
159 static void
160 itc_monotonic (struct timeval *tv)
162 do_gettimeofday (tv);
165 #ifdef ACCOUNT_IRQ
166 static cputime64_t
167 itc_irq_time (void)
169 struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
170 return cpustat->irq;
172 #endif
174 static void
175 itc_idle (void)
177 struct itc *itc;
178 struct timeval tv;
179 unsigned long flags;
180 #ifdef ACCOUNT_IRQ
181 struct timeval tv_irq_before, tv_irq_after;
182 cputime64_t irq_time_before, irq_time_after;
183 #endif
185 #ifdef ITC_PREEMPT_HACK
186 preempt_disable ();
187 #endif
189 /* printk ("idle in %d\n", smp_processor_id ()); */
190 spin_lock_irqsave (&lock, flags);
191 itc = &global_itc[smp_processor_id ()];
192 itc_monotonic (&itc->sleep_started);
193 itc->sleeping = 1;
194 #ifdef ACCOUNT_IRQ
195 irq_time_before = itc_irq_time ();
196 #endif
197 spin_unlock_irqrestore (&lock, flags);
199 #ifdef QUIRK
200 if (orig_pm_idle)
202 orig_pm_idle ();
204 #ifdef CONFIG_X86
205 else
207 fidle_func ();
209 #endif
210 #else
211 if (orig_pm_idle)
213 orig_pm_idle ();
215 else
217 #ifdef CONFIG_X86
218 if (fidle_func)
220 fidle_func ();
222 else
223 #endif
225 default_idle ();
228 #endif
230 spin_lock_irqsave (&lock, flags);
231 itc_monotonic (&tv);
233 #ifdef ACCOUNT_IRQ
234 irq_time_after = itc_irq_time ();
236 cputime_to_timeval (irq_time_before, &tv_irq_before);
237 cputime_to_timeval (irq_time_after, &tv_irq_after);
239 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
240 cpeamb (&itc->cumm_sleep_time, &tv_irq_before, &tv_irq_after);
241 #else
242 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
243 #endif
245 itc->sleeping = 0;
246 spin_unlock_irqrestore (&lock, flags);
247 /* printk ("idle out %d\n", smp_processor_id ()); */
249 #ifdef ITC_PREEMPT_HACK
250 preempt_enable ();
251 #endif
254 /**********************************************************************
256 * File operations
258 **********************************************************************/
259 static int
260 itc_open (struct inode * inode, struct file * file);
262 static int
263 itc_release (struct inode * inode, struct file * file);
265 static int
266 itc_ioctl (struct inode * inode, struct file * file,
267 unsigned int cmd, unsigned long arg);
269 static ssize_t
270 itc_read (struct file * file, char * buf, size_t count, loff_t * ppos);
272 static struct file_operations itc_fops =
274 .owner = THIS_MODULE,
275 .open = itc_open,
276 .release = itc_release,
277 .ioctl = itc_ioctl,
278 .llseek = no_llseek,
279 .read = itc_read,
282 static struct miscdevice itc_misc_dev =
284 .minor = MISC_DYNAMIC_MINOR,
285 .name = "itc",
286 .fops = &itc_fops
289 static int
290 itc_release (struct inode * inode, struct file * filp)
292 itc_enter_bkl ();
293 pm_idle = orig_pm_idle;
294 in_use = 0;
295 itc_leave_bkl ();
296 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
297 /* XXX: 2.4 */
298 #if LINUX_VERSION_CODE > KERNEL_VERSION (2, 6, 26)
299 /* 15c8b6c1aaaf1c4edd67e2f02e4d8e1bd1a51c0d */
300 on_each_cpu (dummy_wakeup, NULL, 1);
301 #else
302 on_each_cpu (dummy_wakeup, NULL, 0, 1);
303 #endif
304 #endif
305 return 0;
308 static int
309 itc_open (struct inode * inode, struct file * filp)
311 int ret = 0;
312 const struct file_operations *old_fops = filp->f_op;
313 unsigned int minor = iminor (inode);
315 if (itc_major)
317 if (minor != 0)
319 return -ENODEV;
323 if (in_use)
325 return -EALREADY;
328 /* old_fops = filp->f_op; */
329 filp->f_op = fops_get (&itc_fops);
330 fops_put (old_fops);
332 itc_enter_bkl ();
333 if (pm_idle != itc_idle)
335 orig_pm_idle = pm_idle;
337 pm_idle = itc_idle;
338 in_use = 1;
339 itc_leave_bkl ();
341 return ret;
344 static ssize_t
345 itc_read (struct file *file, char * buf, size_t count, loff_t * ppos)
347 int i;
348 size_t itemsize = sizeof (global_itc[0].cumm_sleep_time);
349 ssize_t retval = 0;
350 unsigned long flags;
351 struct itc *itc = &global_itc[0];
352 struct timeval tmp[NR_CPUS], *tmpp;
354 tmpp = tmp;
355 if (count < itemsize * num_present_cpus ())
357 printk (KERN_ERR
358 "attempt to read something funny %zu expected %zu(%zu,%u)\n",
359 count, itemsize * num_present_cpus (),
360 itemsize, num_present_cpus ());
361 return -EINVAL;
364 spin_lock_irqsave (&lock, flags);
365 for (i = 0; i < NR_CPUS; ++i, ++itc)
367 if (cpu_present (i))
369 if (itc->sleeping)
371 struct timeval tv;
373 itc_monotonic (&tv);
374 cpeamb (&itc->cumm_sleep_time, &tv, &itc->sleep_started);
375 itc->sleep_started.tv_sec = tv.tv_sec;
376 itc->sleep_started.tv_usec = tv.tv_usec;
379 *tmpp++ = itc->cumm_sleep_time;
380 retval += itemsize;
383 spin_unlock_irqrestore (&lock, flags);
385 if (copy_to_user (buf, tmp, retval))
387 printk (KERN_ERR "failed to write %zu bytes to %p\n",
388 retval, buf);
389 retval = -EFAULT;
391 return retval;
394 /**********************************************************************
396 * ioctl handler
398 **********************************************************************/
399 static int
400 itc_ioctl (struct inode * inode, struct file * filp,
401 unsigned int cmd, unsigned long arg)
403 return -EINVAL;
406 /**********************************************************************
408 * Module constructor
410 **********************************************************************/
411 static __init int
412 init (void)
414 int err;
416 #ifdef CONFIG_X86
417 fidle_func = (void (*) (void)) idle_func;
418 #endif
420 #ifdef QUIRK
421 if (!pm_idle
422 #ifdef CONFIG_X86
423 && !fidle_func
424 #endif
427 printk
428 (KERN_ERR
429 "itc: no idle function\n"
430 "itc: boot kernel with idle=halt option\n"
431 "itc: or specify idle_func (modprobe itc idle_func=<address>)\n");
432 return -ENODEV;
434 #endif
436 if (itc_major)
438 err = register_chrdev (itc_major, DEVNAME, &itc_fops);
439 if (err < 0 || ((itc_major && err) || (!itc_major && !err)))
441 printk (KERN_ERR "itc: register_chrdev failed itc_major=%d err=%d\n",
442 itc_major, err);
443 return -ENODEV;
446 if (!itc_major)
448 itc_major = err;
451 else
453 err = misc_register (&itc_misc_dev);
454 if (err < 0)
456 printk (KERN_ERR "itc: misc_register failed err=%d\n", err);
457 return err;
461 orig_pm_idle = pm_idle;
462 printk
463 (KERN_DEBUG
464 "itc: driver loaded pm_idle=%p default_idle=%p"
465 #ifdef CONFIG_X86
466 ", idle_func=%p"
467 #endif
468 "\n",
469 pm_idle
470 #ifdef QUIRK
471 , NULL
472 #else
473 , default_idle
474 #endif
475 #ifdef CONFIG_X86
476 , fidle_func
477 #endif
479 printk (KERN_DEBUG "itc: CPUs(%d present=%d online=%d)"
480 #ifdef QUIRK
481 " Q"
482 #endif
483 #ifdef CONFIG_APM
484 " A"
485 #endif
486 #ifdef CONFIG_SMP
487 " S"
488 #endif
489 #ifdef CONFIG_PREEMPT
490 " P"
491 #endif
492 "\n",
493 NR_CPUS, num_present_cpus (), num_online_cpus ());
494 return 0;
497 /**********************************************************************
499 * Module destructor
501 **********************************************************************/
502 static __exit void
503 fini (void)
505 printk (KERN_DEBUG "itc: unloading (resetting pm_idle to %p)\n",
506 orig_pm_idle);
507 if (itc_major)
509 unregister_chrdev (itc_major, DEVNAME);
511 else
513 misc_deregister (&itc_misc_dev);
515 printk (KERN_DEBUG "itc: unloaded\n");
518 module_init (init);
519 module_exit (fini);