Commit | Line | Data |
---|---|---|
cff65c4f | 1 | /* |
2eb5f31b AI |
2 | * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) |
3 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | |
4 | * Copyright (C) 2012-2014 Cisco Systems | |
ba180fd4 | 5 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4 LT |
6 | * Licensed under the GPL |
7 | */ | |
8 | ||
c5d4bb17 | 9 | #include <linux/clockchips.h> |
7d195a54 | 10 | #include <linux/init.h> |
c5d4bb17 JD |
11 | #include <linux/interrupt.h> |
12 | #include <linux/jiffies.h> | |
2eb5f31b AI |
13 | #include <linux/mm.h> |
14 | #include <linux/sched.h> | |
15 | #include <linux/spinlock.h> | |
c5d4bb17 JD |
16 | #include <linux/threads.h> |
17 | #include <asm/irq.h> | |
18 | #include <asm/param.h> | |
37185b33 AV |
19 | #include <kern_util.h> |
20 | #include <os.h> | |
2eb5f31b | 21 | #include <timer-internal.h> |
1da177e4 | 22 | |
d3c1cfcd | 23 | void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) |
1da177e4 | 24 | { |
31ccc1f5 | 25 | unsigned long flags; |
31ccc1f5 JD |
26 | |
27 | local_irq_save(flags); | |
d2753a6d | 28 | do_IRQ(TIMER_IRQ, regs); |
31ccc1f5 | 29 | local_irq_restore(flags); |
1da177e4 LT |
30 | } |
31 | ||
71b5280b | 32 | static int itimer_shutdown(struct clock_event_device *evt) |
cff65c4f | 33 | { |
2eb5f31b | 34 | os_timer_disable(); |
71b5280b VK |
35 | return 0; |
36 | } | |
31ccc1f5 | 37 | |
71b5280b VK |
38 | static int itimer_set_periodic(struct clock_event_device *evt) |
39 | { | |
2eb5f31b | 40 | os_timer_set_interval(NULL, NULL); |
71b5280b | 41 | return 0; |
cff65c4f GS |
42 | } |
43 | ||
d2753a6d JD |
44 | static int itimer_next_event(unsigned long delta, |
45 | struct clock_event_device *evt) | |
46 | { | |
2eb5f31b | 47 | return os_timer_one_shot(delta); |
d2753a6d JD |
48 | } |
49 | ||
2eb5f31b AI |
50 | static int itimer_one_shot(struct clock_event_device *evt) |
51 | { | |
52 | os_timer_one_shot(1); | |
53 | return 0; | |
54 | } | |
55 | ||
56 | static struct clock_event_device timer_clockevent = { | |
57 | .name = "posix-timer", | |
71b5280b VK |
58 | .rating = 250, |
59 | .cpumask = cpu_all_mask, | |
60 | .features = CLOCK_EVT_FEAT_PERIODIC | | |
61 | CLOCK_EVT_FEAT_ONESHOT, | |
62 | .set_state_shutdown = itimer_shutdown, | |
63 | .set_state_periodic = itimer_set_periodic, | |
2eb5f31b | 64 | .set_state_oneshot = itimer_one_shot, |
71b5280b | 65 | .set_next_event = itimer_next_event, |
2eb5f31b AI |
66 | .shift = 0, |
67 | .max_delta_ns = 0xffffffff, | |
8ab3a284 NS |
68 | .max_delta_ticks = 0xffffffff, |
69 | .min_delta_ns = TIMER_MIN_DELTA, | |
70 | .min_delta_ticks = TIMER_MIN_DELTA, // microsecond resolution should be enough for anyone, same as 640K RAM | |
71b5280b | 71 | .irq = 0, |
2eb5f31b | 72 | .mult = 1, |
31ccc1f5 JD |
73 | }; |
74 | ||
75 | static irqreturn_t um_timer(int irq, void *dev) | |
1da177e4 | 76 | { |
2eb5f31b AI |
77 | if (get_current()->mm != NULL) |
78 | { | |
79 | /* userspace - relay signal, results in correct userspace timers */ | |
80 | os_alarm_process(get_current()->mm->context.id.u.pid); | |
81 | } | |
82 | ||
83 | (*timer_clockevent.event_handler)(&timer_clockevent); | |
cff65c4f | 84 | |
572e6147 | 85 | return IRQ_HANDLED; |
1da177e4 LT |
86 | } |
87 | ||
a5a1d1c2 | 88 | static u64 timer_read(struct clocksource *cs) |
791a644a | 89 | { |
2eb5f31b | 90 | return os_nsecs() / TIMER_MULTIPLIER; |
791a644a JD |
91 | } |
92 | ||
2eb5f31b AI |
93 | static struct clocksource timer_clocksource = { |
94 | .name = "timer", | |
791a644a | 95 | .rating = 300, |
2eb5f31b | 96 | .read = timer_read, |
791a644a | 97 | .mask = CLOCKSOURCE_MASK(64), |
791a644a JD |
98 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
99 | }; | |
100 | ||
69b73e95 | 101 | static void __init um_timer_setup(void) |
aceb3434 JD |
102 | { |
103 | int err; | |
104 | ||
2eb5f31b | 105 | err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL); |
ba180fd4 | 106 | if (err != 0) |
537ae946 | 107 | printk(KERN_ERR "register_timer : request_irq failed - " |
aceb3434 JD |
108 | "errno = %d\n", -err); |
109 | ||
2eb5f31b AI |
110 | err = os_timer_create(NULL); |
111 | if (err != 0) { | |
112 | printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); | |
113 | return; | |
114 | } | |
115 | ||
116 | err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER); | |
791a644a | 117 | if (err) { |
60d687e7 | 118 | printk(KERN_ERR "clocksource_register_hz returned %d\n", err); |
791a644a JD |
119 | return; |
120 | } | |
2eb5f31b | 121 | clockevents_register_device(&timer_clockevent); |
aceb3434 JD |
122 | } |
123 | ||
9f31f577 JS |
124 | void read_persistent_clock(struct timespec *ts) |
125 | { | |
2eb5f31b | 126 | long long nsecs = os_persistent_clock_emulation(); |
b2923076 | 127 | |
9f31f577 JS |
128 | set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, |
129 | nsecs % NSEC_PER_SEC); | |
130 | } | |
131 | ||
31ccc1f5 | 132 | void __init time_init(void) |
aceb3434 | 133 | { |
2eb5f31b | 134 | timer_set_signal_handler(); |
69b73e95 | 135 | late_time_init = um_timer_setup; |
1da177e4 | 136 | } |