| .. | .. |
|---|
| 10 | 10 | * |
|---|
| 11 | 11 | */ |
|---|
| 12 | 12 | |
|---|
| 13 | +#include <linux/clocksource.h> |
|---|
| 13 | 14 | #include <linux/clockchips.h> |
|---|
| 14 | 15 | #include <linux/interrupt.h> |
|---|
| 15 | 16 | #include <linux/irq.h> |
|---|
| .. | .. |
|---|
| 32 | 33 | #ifdef CONFIG_FRAME_POINTER |
|---|
| 33 | 34 | return *(unsigned long *)(regs->bp + sizeof(long)); |
|---|
| 34 | 35 | #else |
|---|
| 35 | | - unsigned long *sp = |
|---|
| 36 | | - (unsigned long *)kernel_stack_pointer(regs); |
|---|
| 36 | + unsigned long *sp = (unsigned long *)regs->sp; |
|---|
| 37 | 37 | /* |
|---|
| 38 | 38 | * Return address is either directly at stack pointer |
|---|
| 39 | 39 | * or above a saved flags. Eflags has bits 22-31 zero, |
|---|
| .. | .. |
|---|
| 58 | 58 | return IRQ_HANDLED; |
|---|
| 59 | 59 | } |
|---|
| 60 | 60 | |
|---|
| 61 | | -static struct irqaction irq0 = { |
|---|
| 62 | | - .handler = timer_interrupt, |
|---|
| 63 | | - .flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER, |
|---|
| 64 | | - .name = "timer" |
|---|
| 65 | | -}; |
|---|
| 66 | | - |
|---|
| 67 | 61 | static void __init setup_default_timer_irq(void) |
|---|
| 68 | 62 | { |
|---|
| 63 | + unsigned long flags = IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER; |
|---|
| 64 | + |
|---|
| 69 | 65 | /* |
|---|
| 70 | | - * Unconditionally register the legacy timer; even without legacy |
|---|
| 71 | | - * PIC/PIT we need this for the HPET0 in legacy replacement mode. |
|---|
| 66 | + * Unconditionally register the legacy timer interrupt; even |
|---|
| 67 | + * without legacy PIC/PIT we need this for the HPET0 in legacy |
|---|
| 68 | + * replacement mode. |
|---|
| 72 | 69 | */ |
|---|
| 73 | | - if (setup_irq(0, &irq0)) |
|---|
| 70 | + if (request_irq(0, timer_interrupt, flags, "timer", NULL)) |
|---|
| 74 | 71 | pr_info("Failed to register legacy timer interrupt\n"); |
|---|
| 75 | 72 | } |
|---|
| 76 | 73 | |
|---|
| 77 | 74 | /* Default timer init function */ |
|---|
| 78 | 75 | void __init hpet_time_init(void) |
|---|
| 79 | 76 | { |
|---|
| 80 | | - if (!hpet_enable()) |
|---|
| 81 | | - setup_pit_timer(); |
|---|
| 77 | + if (!hpet_enable()) { |
|---|
| 78 | + if (!pit_timer_init()) |
|---|
| 79 | + return; |
|---|
| 80 | + } |
|---|
| 81 | + |
|---|
| 82 | 82 | setup_default_timer_irq(); |
|---|
| 83 | 83 | } |
|---|
| 84 | 84 | |
|---|
| 85 | 85 | static __init void x86_late_time_init(void) |
|---|
| 86 | 86 | { |
|---|
| 87 | | - x86_init.timers.timer_init(); |
|---|
| 88 | 87 | /* |
|---|
| 89 | | - * After PIT/HPET timers init, select and setup |
|---|
| 90 | | - * the final interrupt mode for delivering IRQs. |
|---|
| 88 | + * Before PIT/HPET init, select the interrupt mode. This is required |
|---|
| 89 | + * to make the decision whether PIT should be initialized correct. |
|---|
| 90 | + */ |
|---|
| 91 | + x86_init.irqs.intr_mode_select(); |
|---|
| 92 | + |
|---|
| 93 | + /* Setup the legacy timers */ |
|---|
| 94 | + x86_init.timers.timer_init(); |
|---|
| 95 | + |
|---|
| 96 | + /* |
|---|
| 97 | + * After PIT/HPET timers init, set up the final interrupt mode for |
|---|
| 98 | + * delivering IRQs. |
|---|
| 91 | 99 | */ |
|---|
| 92 | 100 | x86_init.irqs.intr_mode_init(); |
|---|
| 93 | 101 | tsc_init(); |
|---|
| 102 | + |
|---|
| 103 | + if (static_cpu_has(X86_FEATURE_WAITPKG)) |
|---|
| 104 | + use_tpause_delay(); |
|---|
| 94 | 105 | } |
|---|
| 95 | 106 | |
|---|
| 96 | 107 | /* |
|---|
| .. | .. |
|---|
| 101 | 112 | { |
|---|
| 102 | 113 | late_time_init = x86_late_time_init; |
|---|
| 103 | 114 | } |
|---|
| 115 | + |
|---|
| 116 | +/* |
|---|
| 117 | + * Sanity check the vdso related archdata content. |
|---|
| 118 | + */ |
|---|
| 119 | +void clocksource_arch_init(struct clocksource *cs) |
|---|
| 120 | +{ |
|---|
| 121 | + if (cs->vdso_clock_mode == VDSO_CLOCKMODE_NONE) |
|---|
| 122 | + return; |
|---|
| 123 | + |
|---|
| 124 | + if (cs->mask != CLOCKSOURCE_MASK(64)) { |
|---|
| 125 | + pr_warn("clocksource %s registered with invalid mask %016llx for VDSO. Disabling VDSO support.\n", |
|---|
| 126 | + cs->name, cs->mask); |
|---|
| 127 | + cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE; |
|---|
| 128 | + } |
|---|
| 129 | +} |
|---|