aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/time.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-10-16 04:27:24 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:08 -0400
commit31ccc1f524b626abcf5e043ad32b881219223c34 (patch)
tree419284a887fad9dab58969531cf6c53ca0402944 /arch/um/kernel/time.c
parentd83d2aa9485d996cfd89f04389b419c6727faacb (diff)
uml: GENERIC_CLOCKEVENTS support
Enable CONFIG_GENERIC_CLOCKEVENTS. timer_irq gets its name changed to timer_handler, and becomes the recipient of timer signals. The clock_event_device is set up to imitate the current ticking clock, i.e. CLOCK_EVT_FEAT_ONESHOT is not enabled yet. disable_timer now doesn't ignore SIGALRM and SIGVTALRM because that breaks delay calibration. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/kernel/time.c')
-rw-r--r--arch/um/kernel/time.c101
1 files changed, 48 insertions, 53 deletions
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 7678bcf830ba..01678487b999 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -3,6 +3,7 @@
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
6#include "linux/clockchips.h"
6#include "linux/interrupt.h" 7#include "linux/interrupt.h"
7#include "linux/jiffies.h" 8#include "linux/jiffies.h"
8#include "linux/threads.h" 9#include "linux/threads.h"
@@ -24,9 +25,10 @@ static unsigned long long prev_nsecs[NR_CPUS];
24static long long delta[NR_CPUS]; /* Deviation per interval */ 25static long long delta[NR_CPUS]; /* Deviation per interval */
25#endif 26#endif
26 27
27void timer_irq(struct uml_pt_regs *regs) 28void timer_handler(int sig, struct uml_pt_regs *regs)
28{ 29{
29 unsigned long long ticks = 0; 30 unsigned long long ticks = 0;
31 unsigned long flags;
30#ifdef CONFIG_UML_REAL_TIME_CLOCK 32#ifdef CONFIG_UML_REAL_TIME_CLOCK
31 int c = cpu(); 33 int c = cpu();
32 if (prev_nsecs[c]) { 34 if (prev_nsecs[c]) {
@@ -47,89 +49,82 @@ void timer_irq(struct uml_pt_regs *regs)
47#else 49#else
48 ticks = 1; 50 ticks = 1;
49#endif 51#endif
52
53 local_irq_save(flags);
50 while (ticks > 0) { 54 while (ticks > 0) {
51 do_IRQ(TIMER_IRQ, regs); 55 do_IRQ(TIMER_IRQ, regs);
52 ticks--; 56 ticks--;
53 } 57 }
58 local_irq_restore(flags);
54} 59}
55 60
56/* Protects local_offset */ 61static void itimer_set_mode(enum clock_event_mode mode,
57static DEFINE_SPINLOCK(timer_spinlock); 62 struct clock_event_device *evt)
58static unsigned long long local_offset = 0;
59
60static inline unsigned long long get_time(void)
61{ 63{
62 unsigned long long nsecs; 64 switch(mode) {
63 unsigned long flags; 65 case CLOCK_EVT_MODE_PERIODIC:
64 66 set_interval();
65 spin_lock_irqsave(&timer_spinlock, flags); 67 break;
66 nsecs = os_nsecs(); 68
67 nsecs += local_offset; 69 case CLOCK_EVT_MODE_SHUTDOWN:
68 spin_unlock_irqrestore(&timer_spinlock, flags); 70 case CLOCK_EVT_MODE_UNUSED:
69 71 disable_timer();
70 return nsecs; 72 break;
73 case CLOCK_EVT_MODE_ONESHOT:
74 BUG();
75 break;
76
77 case CLOCK_EVT_MODE_RESUME:
78 break;
79 }
71} 80}
72 81
73irqreturn_t um_timer(int irq, void *dev) 82static struct clock_event_device itimer_clockevent = {
83 .name = "itimer",
84 .rating = 250,
85 .cpumask = CPU_MASK_ALL,
86 .features = CLOCK_EVT_FEAT_PERIODIC,
87 .set_mode = itimer_set_mode,
88 .set_next_event = NULL,
89 .shift = 32,
90 .irq = 0,
91};
92
93static irqreturn_t um_timer(int irq, void *dev)
74{ 94{
75 unsigned long long nsecs; 95 (*itimer_clockevent.event_handler)(&itimer_clockevent);
76 unsigned long flags;
77
78 write_seqlock_irqsave(&xtime_lock, flags);
79
80 do_timer(1);
81
82#ifdef CONFIG_UML_REAL_TIME_CLOCK
83 nsecs = get_time();
84#else
85 nsecs = (unsigned long long) xtime.tv_sec * BILLION + xtime.tv_nsec +
86 BILLION / HZ;
87#endif
88 xtime.tv_sec = nsecs / NSEC_PER_SEC;
89 xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
90
91 write_sequnlock_irqrestore(&xtime_lock, flags);
92 96
93 return IRQ_HANDLED; 97 return IRQ_HANDLED;
94} 98}
95 99
96static void register_timer(void) 100static void __init setup_itimer(void)
97{ 101{
98 int err; 102 int err;
99 103
100 timer_init();
101
102 err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL); 104 err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL);
103 if (err != 0) 105 if (err != 0)
104 printk(KERN_ERR "register_timer : request_irq failed - " 106 printk(KERN_ERR "register_timer : request_irq failed - "
105 "errno = %d\n", -err); 107 "errno = %d\n", -err);
106 108
107 err = set_interval(); 109 itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32);
108 if (err != 0) 110 itimer_clockevent.max_delta_ns =
109 printk(KERN_ERR "register_timer : set_interval failed - " 111 clockevent_delta2ns(60 * HZ, &itimer_clockevent);
110 "errno = %d\n", -err); 112 itimer_clockevent.min_delta_ns =
113 clockevent_delta2ns(1, &itimer_clockevent);
114 clockevents_register_device(&itimer_clockevent);
111} 115}
112 116
113extern void (*late_time_init)(void); 117extern void (*late_time_init)(void);
114 118
115void time_init(void) 119void __init time_init(void)
116{ 120{
117 long long nsecs; 121 long long nsecs;
118 122
123 timer_init();
124
119 nsecs = os_nsecs(); 125 nsecs = os_nsecs();
120 set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, 126 set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION,
121 -nsecs % BILLION); 127 -nsecs % BILLION);
122 set_normalized_timespec(&xtime, nsecs / BILLION, nsecs % BILLION); 128 set_normalized_timespec(&xtime, nsecs / BILLION, nsecs % BILLION);
123 late_time_init = register_timer; 129 late_time_init = setup_itimer;
124}
125
126void timer_handler(int sig, struct uml_pt_regs *regs)
127{
128 if (current_thread->cpu == 0)
129 timer_irq(regs);
130 local_irq_disable();
131 irq_enter();
132 update_process_times(regs->is_user);
133 irq_exit();
134 local_irq_enable();
135} 130}