time.c 2.2 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3 4 5 6 7 8
 *  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
L
Linus Torvalds 已提交
9 10 11
 *
 */

T
Thomas Gleixner 已提交
12
#include <linux/clockchips.h>
L
Linus Torvalds 已提交
13
#include <linux/interrupt.h>
14
#include <linux/i8253.h>
L
Linus Torvalds 已提交
15
#include <linux/time.h>
16
#include <linux/export.h>
L
Linus Torvalds 已提交
17 18
#include <linux/mca.h>

19 20
#include <asm/vsyscall.h>
#include <asm/x86_init.h>
T
Thomas Gleixner 已提交
21
#include <asm/i8259.h>
22 23 24
#include <asm/timer.h>
#include <asm/hpet.h>
#include <asm/time.h>
L
Linus Torvalds 已提交
25

26
#ifdef CONFIG_X86_64
27
DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
28 29
#endif

L
Linus Torvalds 已提交
30 31 32 33
unsigned long profile_pc(struct pt_regs *regs)
{
	unsigned long pc = instruction_pointer(regs);

G
Glauber Costa 已提交
34
	if (!user_mode_vm(regs) && in_lock_functions(pc)) {
35
#ifdef CONFIG_FRAME_POINTER
G
Glauber Costa 已提交
36
		return *(unsigned long *)(regs->bp + sizeof(long));
37
#else
38 39
		unsigned long *sp =
			(unsigned long *)kernel_stack_pointer(regs);
40 41 42 43 44
		/*
		 * Return address is either directly at stack pointer
		 * or above a saved flags. Eflags has bits 22-31 zero,
		 * kernel addresses don't.
		 */
45
		if (sp[0] >> 22)
46 47 48 49 50
			return sp[0];
		if (sp[1] >> 22)
			return sp[1];
#endif
	}
L
Linus Torvalds 已提交
51 52 53 54 55
	return pc;
}
EXPORT_SYMBOL(profile_pc);

/*
56
 * Default timer interrupt handler for PIT/HPET
L
Linus Torvalds 已提交
57
 */
58
static irqreturn_t timer_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
59
{
T
Thomas Gleixner 已提交
60
	global_clock_event->event_handler(global_clock_event);
L
Linus Torvalds 已提交
61

62 63 64
	/* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
	if (MCA_bus)
		outb_p(inb_p(0x61)| 0x80, 0x61);
L
Linus Torvalds 已提交
65 66 67 68

	return IRQ_HANDLED;
}

69 70 71 72 73 74 75 76 77 78 79 80
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 */
Z
Zachary Amsden 已提交
81
void __init hpet_time_init(void)
L
Linus Torvalds 已提交
82
{
83 84
	if (!hpet_enable())
		setup_pit_timer();
85 86 87
	setup_default_timer_irq();
}

88
static __init void x86_late_time_init(void)
89 90
{
	x86_init.timers.timer_init();
91
	tsc_init();
L
Linus Torvalds 已提交
92 93
}

Z
Zachary Amsden 已提交
94
/*
95 96
 * Initialize TSC and delay the periodic timer init to
 * late x86_late_time_init() so ioremap works.
Z
Zachary Amsden 已提交
97
 */
L
Linus Torvalds 已提交
98 99
void __init time_init(void)
{
100
	late_time_init = x86_late_time_init;
L
Linus Torvalds 已提交
101
}