1 /* 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 5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 6 * Licensed under the GPL 7 */ 8 9 #include <linux/clockchips.h> 10 #include <linux/init.h> 11 #include <linux/interrupt.h> 12 #include <linux/jiffies.h> 13 #include <linux/mm.h> 14 #include <linux/sched.h> 15 #include <linux/spinlock.h> 16 #include <linux/threads.h> 17 #include <asm/irq.h> 18 #include <asm/param.h> 19 #include <kern_util.h> 20 #include <os.h> 21 #include <timer-internal.h> 22 23 void timer_handler(int sig, struct siginfo *unused_si, 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 int itimer_shutdown(struct clock_event_device *evt) 33 { 34 os_timer_disable(); 35 return 0; 36 } 37 38 static int itimer_set_periodic(struct clock_event_device *evt) 39 { 40 os_timer_set_interval(NULL, NULL); 41 return 0; 42 } 43 44 static int itimer_next_event(unsigned long delta, 45 struct clock_event_device *evt) 46 { 47 return os_timer_one_shot(delta); 48 } 49 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", 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, 64 .set_state_oneshot = itimer_one_shot, 65 .set_next_event = itimer_next_event, 66 .shift = 0, 67 .max_delta_ns = 0xffffffff, 68 .min_delta_ns = TIMER_MIN_DELTA, //microsecond resolution should be enough for anyone, same as 640K RAM 69 .irq = 0, 70 .mult = 1, 71 }; 72 73 static irqreturn_t um_timer(int irq, void *dev) 74 { 75 if (get_current()->mm != NULL) 76 { 77 /* userspace - relay signal, results in correct userspace timers */ 78 os_alarm_process(get_current()->mm->context.id.u.pid); 79 } 80 81 (*timer_clockevent.event_handler)(&timer_clockevent); 82 83 return IRQ_HANDLED; 84 } 85 86 static cycle_t timer_read(struct clocksource *cs) 87 { 88 return os_nsecs() / TIMER_MULTIPLIER; 89 } 90 91 static struct clocksource timer_clocksource = { 92 .name = "timer", 93 .rating = 300, 94 .read = timer_read, 95 .mask = CLOCKSOURCE_MASK(64), 96 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 97 }; 98 99 static void __init timer_setup(void) 100 { 101 int err; 102 103 err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL); 104 if (err != 0) 105 printk(KERN_ERR "register_timer : request_irq failed - " 106 "errno = %d\n", -err); 107 108 err = os_timer_create(NULL); 109 if (err != 0) { 110 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); 111 return; 112 } 113 114 err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER); 115 if (err) { 116 printk(KERN_ERR "clocksource_register_hz returned %d\n", err); 117 return; 118 } 119 clockevents_register_device(&timer_clockevent); 120 } 121 122 void read_persistent_clock(struct timespec *ts) 123 { 124 long long nsecs = os_persistent_clock_emulation(); 125 126 set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, 127 nsecs % NSEC_PER_SEC); 128 } 129 130 void __init time_init(void) 131 { 132 timer_set_signal_handler(); 133 late_time_init = timer_setup; 134 } 135