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 * (NSEC_PER_SEC / 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 / NSEC_PER_SEC, 122 -nsecs % NSEC_PER_SEC); 123 set_normalized_timespec(&xtime, nsecs / NSEC_PER_SEC, 124 nsecs % NSEC_PER_SEC); 125 late_time_init = setup_itimer; 126 } 127