blob: 47f04f4a3464a918850b67573e1a67a7cf5c3dec [file] [log] [blame]
Gennady Sharapovcff65c42006-01-18 17:42:42 -08001/*
Jeff Dikeba180fd2007-10-16 01:27:00 -07002 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 */
5
Jeff Dikec5d4bb12008-02-04 22:31:14 -08006#include <linux/clockchips.h>
Adrian Bunk7d195a52008-04-29 00:59:18 -07007#include <linux/init.h>
Jeff Dikec5d4bb12008-02-04 22:31:14 -08008#include <linux/interrupt.h>
9#include <linux/jiffies.h>
10#include <linux/threads.h>
11#include <asm/irq.h>
12#include <asm/param.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "kern_util.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include "os.h"
15
Jeff Dike31ccc1f2007-10-16 01:27:24 -070016void timer_handler(int sig, struct uml_pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017{
Jeff Dike31ccc1f2007-10-16 01:27:24 -070018 unsigned long flags;
Jeff Dike31ccc1f2007-10-16 01:27:24 -070019
20 local_irq_save(flags);
Jeff Diked2753a62007-10-16 01:27:25 -070021 do_IRQ(TIMER_IRQ, regs);
Jeff Dike31ccc1f2007-10-16 01:27:24 -070022 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070023}
24
Jeff Dike31ccc1f2007-10-16 01:27:24 -070025static void itimer_set_mode(enum clock_event_mode mode,
26 struct clock_event_device *evt)
Gennady Sharapovcff65c42006-01-18 17:42:42 -080027{
Jeff Dikec5d4bb12008-02-04 22:31:14 -080028 switch (mode) {
Jeff Dike31ccc1f2007-10-16 01:27:24 -070029 case CLOCK_EVT_MODE_PERIODIC:
30 set_interval();
31 break;
Gennady Sharapovcff65c42006-01-18 17:42:42 -080032
Jeff Dike31ccc1f2007-10-16 01:27:24 -070033 case CLOCK_EVT_MODE_SHUTDOWN:
34 case CLOCK_EVT_MODE_UNUSED:
Jeff Dike31ccc1f2007-10-16 01:27:24 -070035 case CLOCK_EVT_MODE_ONESHOT:
Jeff Diked2753a62007-10-16 01:27:25 -070036 disable_timer();
Jeff Dike31ccc1f2007-10-16 01:27:24 -070037 break;
Gennady Sharapovcff65c42006-01-18 17:42:42 -080038
Jeff Dike31ccc1f2007-10-16 01:27:24 -070039 case CLOCK_EVT_MODE_RESUME:
40 break;
41 }
Gennady Sharapovcff65c42006-01-18 17:42:42 -080042}
43
Jeff Diked2753a62007-10-16 01:27:25 -070044static int itimer_next_event(unsigned long delta,
45 struct clock_event_device *evt)
46{
47 return timer_one_shot(delta + 1);
48}
49
Jeff Dike31ccc1f2007-10-16 01:27:24 -070050static struct clock_event_device itimer_clockevent = {
51 .name = "itimer",
52 .rating = 250,
53 .cpumask = CPU_MASK_ALL,
Jeff Diked2753a62007-10-16 01:27:25 -070054 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
Jeff Dike31ccc1f2007-10-16 01:27:24 -070055 .set_mode = itimer_set_mode,
Jeff Diked2753a62007-10-16 01:27:25 -070056 .set_next_event = itimer_next_event,
Jeff Dike31ccc1f2007-10-16 01:27:24 -070057 .shift = 32,
58 .irq = 0,
59};
60
61static irqreturn_t um_timer(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
Jeff Dike31ccc1f2007-10-16 01:27:24 -070063 (*itimer_clockevent.event_handler)(&itimer_clockevent);
Gennady Sharapovcff65c42006-01-18 17:42:42 -080064
Jeff Dike572e6142006-06-30 01:55:56 -070065 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066}
67
Jeff Dike791a6442007-10-16 01:27:25 -070068static cycle_t itimer_read(void)
69{
Jeff Dikecfd28f62008-05-12 14:01:53 -070070 return os_nsecs() / 1000;
Jeff Dike791a6442007-10-16 01:27:25 -070071}
72
73static struct clocksource itimer_clocksource = {
74 .name = "itimer",
75 .rating = 300,
76 .read = itimer_read,
77 .mask = CLOCKSOURCE_MASK(64),
Jeff Dikecfd28f62008-05-12 14:01:53 -070078 .mult = 1000,
Jeff Dike791a6442007-10-16 01:27:25 -070079 .shift = 0,
80 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
81};
82
Jeff Dike31ccc1f2007-10-16 01:27:24 -070083static void __init setup_itimer(void)
Jeff Dikeaceb3432006-07-10 04:45:05 -070084{
85 int err;
86
87 err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL);
Jeff Dikeba180fd2007-10-16 01:27:00 -070088 if (err != 0)
Jeff Dike537ae942006-09-25 23:33:05 -070089 printk(KERN_ERR "register_timer : request_irq failed - "
Jeff Dikeaceb3432006-07-10 04:45:05 -070090 "errno = %d\n", -err);
91
Jeff Dike31ccc1f2007-10-16 01:27:24 -070092 itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32);
93 itimer_clockevent.max_delta_ns =
94 clockevent_delta2ns(60 * HZ, &itimer_clockevent);
95 itimer_clockevent.min_delta_ns =
96 clockevent_delta2ns(1, &itimer_clockevent);
Jeff Dike791a6442007-10-16 01:27:25 -070097 err = clocksource_register(&itimer_clocksource);
98 if (err) {
99 printk(KERN_ERR "clocksource_register returned %d\n", err);
100 return;
101 }
Jeff Dike31ccc1f2007-10-16 01:27:24 -0700102 clockevents_register_device(&itimer_clockevent);
Jeff Dikeaceb3432006-07-10 04:45:05 -0700103}
104
Jeff Dike31ccc1f2007-10-16 01:27:24 -0700105void __init time_init(void)
Jeff Dikeaceb3432006-07-10 04:45:05 -0700106{
107 long long nsecs;
108
Jeff Dike31ccc1f2007-10-16 01:27:24 -0700109 timer_init();
110
Jeff Dikeaceb3432006-07-10 04:45:05 -0700111 nsecs = os_nsecs();
Jeff Dike1a805212007-10-16 01:27:28 -0700112 set_normalized_timespec(&wall_to_monotonic, -nsecs / NSEC_PER_SEC,
113 -nsecs % NSEC_PER_SEC);
114 set_normalized_timespec(&xtime, nsecs / NSEC_PER_SEC,
115 nsecs % NSEC_PER_SEC);
Jeff Dike31ccc1f2007-10-16 01:27:24 -0700116 late_time_init = setup_itimer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}