| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-08-20 15:35:23 +02:00
										 |  |  |  *  Copyright (c) 1991,1992,1995  Linus Torvalds | 
					
						
							|  |  |  |  *  Copyright (c) 1994  Alan Modra | 
					
						
							|  |  |  |  *  Copyright (c) 1995  Markus Kuhn | 
					
						
							|  |  |  |  *  Copyright (c) 1996  Ingo Molnar | 
					
						
							|  |  |  |  *  Copyright (c) 1998  Andrea Arcangeli | 
					
						
							|  |  |  |  *  Copyright (c) 2002,2006  Vojtech Pavlik | 
					
						
							|  |  |  |  *  Copyright (c) 2003  Andi Kleen | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-20 15:28:50 +02:00
										 |  |  | #include <linux/clockchips.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/interrupt.h>
 | 
					
						
							| 
									
										
										
										
											2011-06-01 19:04:57 +01:00
										 |  |  | #include <linux/i8253.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/time.h>
 | 
					
						
							| 
									
										
										
										
											2011-05-26 12:22:53 -04:00
										 |  |  | #include <linux/export.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-20 15:35:23 +02:00
										 |  |  | #include <asm/vsyscall.h>
 | 
					
						
							|  |  |  | #include <asm/x86_init.h>
 | 
					
						
							| 
									
										
										
										
											2009-08-20 15:28:50 +02:00
										 |  |  | #include <asm/i8259.h>
 | 
					
						
							| 
									
										
										
										
											2009-08-20 15:35:23 +02:00
										 |  |  | #include <asm/timer.h>
 | 
					
						
							|  |  |  | #include <asm/hpet.h>
 | 
					
						
							|  |  |  | #include <asm/time.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-20 16:07:40 +02:00
										 |  |  | #ifdef CONFIG_X86_64
 | 
					
						
							| 
									
										
										
										
											2011-05-23 09:31:24 -04:00
										 |  |  | DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES; | 
					
						
							| 
									
										
										
										
											2009-08-20 16:07:40 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | unsigned long profile_pc(struct pt_regs *regs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long pc = instruction_pointer(regs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-11 13:48:07 -03:00
										 |  |  | 	if (!user_mode_vm(regs) && in_lock_functions(pc)) { | 
					
						
							| 
									
										
										
										
											2006-09-26 10:52:28 +02:00
										 |  |  | #ifdef CONFIG_FRAME_POINTER
 | 
					
						
							| 
									
										
										
										
											2008-07-11 16:06:40 -03:00
										 |  |  | 		return *(unsigned long *)(regs->bp + sizeof(long)); | 
					
						
							| 
									
										
										
										
											2006-09-26 10:52:28 +02:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2009-10-12 11:32:31 -07:00
										 |  |  | 		unsigned long *sp = | 
					
						
							|  |  |  | 			(unsigned long *)kernel_stack_pointer(regs); | 
					
						
							| 
									
										
										
										
											2009-08-21 13:24:08 +02:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Return address is either directly at stack pointer | 
					
						
							|  |  |  | 		 * or above a saved flags. Eflags has bits 22-31 zero, | 
					
						
							|  |  |  | 		 * kernel addresses don't. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2008-01-30 13:30:26 +01:00
										 |  |  | 		if (sp[0] >> 22) | 
					
						
							| 
									
										
										
										
											2006-09-26 10:52:28 +02:00
										 |  |  | 			return sp[0]; | 
					
						
							|  |  |  | 		if (sp[1] >> 22) | 
					
						
							|  |  |  | 			return sp[1]; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return pc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(profile_pc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-08-20 16:07:40 +02:00
										 |  |  |  * Default timer interrupt handler for PIT/HPET | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2009-08-19 15:37:03 +02:00
										 |  |  | static irqreturn_t timer_interrupt(int irq, void *dev_id) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-08-20 15:28:50 +02:00
										 |  |  | 	global_clock_event->event_handler(global_clock_event); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-19 15:37:03 +02:00
										 |  |  | static struct irqaction irq0  = { | 
					
						
							|  |  |  | 	.handler = timer_interrupt, | 
					
						
							|  |  |  | 	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER, | 
					
						
							|  |  |  | 	.name = "timer" | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void __init setup_default_timer_irq(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	setup_irq(0, &irq0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Default timer init function */ | 
					
						
							| 
									
										
										
										
											2007-03-05 00:30:39 -08:00
										 |  |  | void __init hpet_time_init(void) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-02-16 01:28:04 -08:00
										 |  |  | 	if (!hpet_enable()) | 
					
						
							|  |  |  | 		setup_pit_timer(); | 
					
						
							| 
									
										
										
										
											2009-08-19 15:37:03 +02:00
										 |  |  | 	setup_default_timer_irq(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-16 08:42:26 +02:00
										 |  |  | static __init void x86_late_time_init(void) | 
					
						
							| 
									
										
										
										
											2009-08-19 15:37:03 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	x86_init.timers.timer_init(); | 
					
						
							| 
									
										
										
										
											2009-08-20 16:51:07 +02:00
										 |  |  | 	tsc_init(); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-05 00:30:39 -08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-08-19 15:37:03 +02:00
										 |  |  |  * Initialize TSC and delay the periodic timer init to | 
					
						
							|  |  |  |  * late x86_late_time_init() so ioremap works. | 
					
						
							| 
									
										
										
										
											2007-03-05 00:30:39 -08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | void __init time_init(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-08-19 15:37:03 +02:00
										 |  |  | 	late_time_init = x86_late_time_init; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } |