uml: tickless support
[linux-2.6] / arch / um / kernel / time.c
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/clockchips.h"
7 #include "linux/interrupt.h"
8 #include "linux/jiffies.h"
9 #include "linux/threads.h"
10 #include "asm/irq.h"
11 #include "asm/param.h"
12 #include "kern_util.h"
13 #include "os.h"
14
15 /*
16  * Scheduler clock - returns current time in nanosec units.
17  */
18 unsigned long long sched_clock(void)
19 {
20         return (unsigned long long)jiffies_64 * (1000000000 / HZ);
21 }
22
23 void timer_handler(int sig, struct uml_pt_regs *regs)
24 {
25         unsigned long flags;
26
27         local_irq_save(flags);
28         do_IRQ(TIMER_IRQ, regs);
29         local_irq_restore(flags);
30 }
31
32 static void itimer_set_mode(enum clock_event_mode mode,
33                             struct clock_event_device *evt)
34 {
35         switch(mode) {
36         case CLOCK_EVT_MODE_PERIODIC:
37                 set_interval();
38                 break;
39
40         case CLOCK_EVT_MODE_SHUTDOWN:
41         case CLOCK_EVT_MODE_UNUSED:
42         case CLOCK_EVT_MODE_ONESHOT:
43                 disable_timer();
44                 break;
45
46         case CLOCK_EVT_MODE_RESUME:
47                 break;
48         }
49 }
50
51 static int itimer_next_event(unsigned long delta,
52                              struct clock_event_device *evt)
53 {
54         return timer_one_shot(delta + 1);
55 }
56
57 static struct clock_event_device itimer_clockevent = {
58         .name           = "itimer",
59         .rating         = 250,
60         .cpumask        = CPU_MASK_ALL,
61         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
62         .set_mode       = itimer_set_mode,
63         .set_next_event = itimer_next_event,
64         .shift          = 32,
65         .irq            = 0,
66 };
67
68 static irqreturn_t um_timer(int irq, void *dev)
69 {
70         (*itimer_clockevent.event_handler)(&itimer_clockevent);
71
72         return IRQ_HANDLED;
73 }
74
75 static cycle_t itimer_read(void)
76 {
77         return os_nsecs();
78 }
79
80 static struct clocksource itimer_clocksource = {
81         .name           = "itimer",
82         .rating         = 300,
83         .read           = itimer_read,
84         .mask           = CLOCKSOURCE_MASK(64),
85         .mult           = 1,
86         .shift          = 0,
87         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
88 };
89
90 static void __init setup_itimer(void)
91 {
92         int err;
93
94         err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL);
95         if (err != 0)
96                 printk(KERN_ERR "register_timer : request_irq failed - "
97                        "errno = %d\n", -err);
98
99         itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32);
100         itimer_clockevent.max_delta_ns =
101                 clockevent_delta2ns(60 * HZ, &itimer_clockevent);
102         itimer_clockevent.min_delta_ns =
103                 clockevent_delta2ns(1, &itimer_clockevent);
104         err = clocksource_register(&itimer_clocksource);
105         if (err) {
106                 printk(KERN_ERR "clocksource_register returned %d\n", err);
107                 return;
108         }
109         clockevents_register_device(&itimer_clockevent);
110 }
111
112 extern void (*late_time_init)(void);
113
114 void __init time_init(void)
115 {
116         long long nsecs;
117
118         timer_init();
119
120         nsecs = os_nsecs();
121         set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION,
122                                 -nsecs % BILLION);
123         set_normalized_timespec(&xtime, nsecs / BILLION, nsecs % BILLION);
124         late_time_init = setup_itimer;
125 }