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 .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 71 .irq = 0, 72 .mult = 1, 73 }; 74 75 static irqreturn_t um_timer(int irq, void *dev) 76 { 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); 84 85 return IRQ_HANDLED; 86 } 87 88 static u64 timer_read(struct clocksource *cs) 89 { 90 return os_nsecs() / TIMER_MULTIPLIER; 91 } 92 93 static struct clocksource timer_clocksource = { 94 .name = "timer", 95 .rating = 300, 96 .read = timer_read, 97 .mask = CLOCKSOURCE_MASK(64), 98 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 99 }; 100 101 static void __init um_timer_setup(void) 102 { 103 int err; 104 105 err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL); 106 if (err != 0) 107 printk(KERN_ERR "register_timer : request_irq failed - " 108 "errno = %d\n", -err); 109 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); 117 if (err) { 118 printk(KERN_ERR "clocksource_register_hz returned %d\n", err); 119 return; 120 } 121 clockevents_register_device(&timer_clockevent); 122 } 123 124 void read_persistent_clock(struct timespec *ts) 125 { 126 long long nsecs = os_persistent_clock_emulation(); 127 128 set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, 129 nsecs % NSEC_PER_SEC); 130 } 131 132 void __init time_init(void) 133 { 134 timer_set_signal_handler(); 135 late_time_init = um_timer_setup; 136 } 137