| 
									
										
										
										
											2006-01-18 17:42:42 -08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:00 -07:00
										 |  |  |  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * Licensed under the GPL | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-04 22:31:14 -08:00
										 |  |  | #include <linux/clockchips.h>
 | 
					
						
							| 
									
										
										
										
											2008-04-29 00:59:18 -07:00
										 |  |  | #include <linux/init.h>
 | 
					
						
							| 
									
										
										
										
											2008-02-04 22:31:14 -08:00
										 |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | #include <linux/jiffies.h>
 | 
					
						
							|  |  |  | #include <linux/threads.h>
 | 
					
						
							|  |  |  | #include <asm/irq.h>
 | 
					
						
							|  |  |  | #include <asm/param.h>
 | 
					
						
							| 
									
										
										
										
											2012-10-08 03:27:32 +01:00
										 |  |  | #include <kern_util.h>
 | 
					
						
							|  |  |  | #include <os.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 00:49:17 +02:00
										 |  |  | void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local_irq_save(flags); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | 	do_IRQ(TIMER_IRQ, regs); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	local_irq_restore(flags); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | static void itimer_set_mode(enum clock_event_mode mode, | 
					
						
							|  |  |  | 			    struct clock_event_device *evt) | 
					
						
							| 
									
										
										
										
											2006-01-18 17:42:42 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-04 22:31:14 -08:00
										 |  |  | 	switch (mode) { | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	case CLOCK_EVT_MODE_PERIODIC: | 
					
						
							|  |  |  | 		set_interval(); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_SHUTDOWN: | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_UNUSED: | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_ONESHOT: | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | 		disable_timer(); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CLOCK_EVT_MODE_RESUME: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-01-18 17:42:42 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | static int itimer_next_event(unsigned long delta, | 
					
						
							|  |  |  | 			     struct clock_event_device *evt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return timer_one_shot(delta + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | static struct clock_event_device itimer_clockevent = { | 
					
						
							|  |  |  | 	.name		= "itimer", | 
					
						
							|  |  |  | 	.rating		= 250, | 
					
						
							| 
									
										
										
										
											2008-12-13 21:20:26 +10:30
										 |  |  | 	.cpumask	= cpu_all_mask, | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | 	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	.set_mode	= itimer_set_mode, | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | 	.set_next_event = itimer_next_event, | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	.shift		= 32, | 
					
						
							|  |  |  | 	.irq		= 0, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t um_timer(int irq, void *dev) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	(*itimer_clockevent.event_handler)(&itimer_clockevent); | 
					
						
							| 
									
										
										
										
											2006-01-18 17:42:42 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-30 01:55:56 -07:00
										 |  |  | 	return IRQ_HANDLED; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-21 12:24:00 -07:00
										 |  |  | static cycle_t itimer_read(struct clocksource *cs) | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-12 14:01:53 -07:00
										 |  |  | 	return os_nsecs() / 1000; | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct clocksource itimer_clocksource = { | 
					
						
							|  |  |  | 	.name		= "itimer", | 
					
						
							|  |  |  | 	.rating		= 300, | 
					
						
							|  |  |  | 	.read		= itimer_read, | 
					
						
							|  |  |  | 	.mask		= CLOCKSOURCE_MASK(64), | 
					
						
							|  |  |  | 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | static void __init setup_itimer(void) | 
					
						
							| 
									
										
										
										
											2006-07-10 04:45:05 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 16:58:46 +08:00
										 |  |  | 	err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:00 -07:00
										 |  |  | 	if (err != 0) | 
					
						
							| 
									
										
										
										
											2006-09-25 23:33:05 -07:00
										 |  |  | 		printk(KERN_ERR "register_timer : request_irq failed - " | 
					
						
							| 
									
										
										
										
											2006-07-10 04:45:05 -07:00
										 |  |  | 		       "errno = %d\n", -err); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32); | 
					
						
							|  |  |  | 	itimer_clockevent.max_delta_ns = | 
					
						
							|  |  |  | 		clockevent_delta2ns(60 * HZ, &itimer_clockevent); | 
					
						
							|  |  |  | 	itimer_clockevent.min_delta_ns = | 
					
						
							|  |  |  | 		clockevent_delta2ns(1, &itimer_clockevent); | 
					
						
							| 
									
										
										
										
											2010-04-26 20:25:16 -07:00
										 |  |  | 	err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | 	if (err) { | 
					
						
							| 
									
										
										
										
											2010-04-26 20:25:16 -07:00
										 |  |  | 		printk(KERN_ERR "clocksource_register_hz returned %d\n", err); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:25 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	clockevents_register_device(&itimer_clockevent); | 
					
						
							| 
									
										
										
										
											2006-07-10 04:45:05 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 17:56:24 -07:00
										 |  |  | void read_persistent_clock(struct timespec *ts) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-03 20:34:48 +02:00
										 |  |  | 	long long nsecs = os_nsecs(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 17:56:24 -07:00
										 |  |  | 	set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, | 
					
						
							|  |  |  | 				nsecs % NSEC_PER_SEC); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | void __init time_init(void) | 
					
						
							| 
									
										
										
										
											2006-07-10 04:45:05 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-16 01:27:24 -07:00
										 |  |  | 	timer_init(); | 
					
						
							|  |  |  | 	late_time_init = setup_itimer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } |