Commit 246b625243c5e2889e97098662ec069f1ebcac9d
Committed by
Greg Kroah-Hartman
1 parent
ec987a13d5
x86, hyperv: Mark the Hyper-V clocksource as being continuous
commit 32c6590d126836a062b3140ed52d898507987017 upstream. The Hyper-V clocksource is continuous; mark it accordingly. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Acked-by: jasowang@redhat.com Cc: gregkh@linuxfoundation.org Cc: devel@linuxdriverproject.org Cc: olaf@aepfle.de Cc: apw@canonical.com Link: http://lkml.kernel.org/r/1421108762-3331-1-git-send-email-kys@microsoft.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 1 additions and 0 deletions Inline Diff
arch/x86/kernel/cpu/mshyperv.c
1 | /* | 1 | /* |
2 | * HyperV Detection code. | 2 | * HyperV Detection code. |
3 | * | 3 | * |
4 | * Copyright (C) 2010, Novell, Inc. | 4 | * Copyright (C) 2010, Novell, Inc. |
5 | * Author : K. Y. Srinivasan <ksrinivasan@novell.com> | 5 | * Author : K. Y. Srinivasan <ksrinivasan@novell.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; version 2 of the License. | 9 | * the Free Software Foundation; version 2 of the License. |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/time.h> | 14 | #include <linux/time.h> |
15 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/hardirq.h> | 17 | #include <linux/hardirq.h> |
18 | #include <linux/efi.h> | 18 | #include <linux/efi.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <asm/processor.h> | 21 | #include <asm/processor.h> |
22 | #include <asm/hypervisor.h> | 22 | #include <asm/hypervisor.h> |
23 | #include <asm/hyperv.h> | 23 | #include <asm/hyperv.h> |
24 | #include <asm/mshyperv.h> | 24 | #include <asm/mshyperv.h> |
25 | #include <asm/desc.h> | 25 | #include <asm/desc.h> |
26 | #include <asm/idle.h> | 26 | #include <asm/idle.h> |
27 | #include <asm/irq_regs.h> | 27 | #include <asm/irq_regs.h> |
28 | #include <asm/i8259.h> | 28 | #include <asm/i8259.h> |
29 | #include <asm/apic.h> | 29 | #include <asm/apic.h> |
30 | #include <asm/timer.h> | 30 | #include <asm/timer.h> |
31 | 31 | ||
32 | struct ms_hyperv_info ms_hyperv; | 32 | struct ms_hyperv_info ms_hyperv; |
33 | EXPORT_SYMBOL_GPL(ms_hyperv); | 33 | EXPORT_SYMBOL_GPL(ms_hyperv); |
34 | 34 | ||
35 | #if IS_ENABLED(CONFIG_HYPERV) | 35 | #if IS_ENABLED(CONFIG_HYPERV) |
36 | static void (*vmbus_handler)(void); | 36 | static void (*vmbus_handler)(void); |
37 | 37 | ||
38 | void hyperv_vector_handler(struct pt_regs *regs) | 38 | void hyperv_vector_handler(struct pt_regs *regs) |
39 | { | 39 | { |
40 | struct pt_regs *old_regs = set_irq_regs(regs); | 40 | struct pt_regs *old_regs = set_irq_regs(regs); |
41 | 41 | ||
42 | irq_enter(); | 42 | irq_enter(); |
43 | exit_idle(); | 43 | exit_idle(); |
44 | 44 | ||
45 | inc_irq_stat(irq_hv_callback_count); | 45 | inc_irq_stat(irq_hv_callback_count); |
46 | if (vmbus_handler) | 46 | if (vmbus_handler) |
47 | vmbus_handler(); | 47 | vmbus_handler(); |
48 | 48 | ||
49 | irq_exit(); | 49 | irq_exit(); |
50 | set_irq_regs(old_regs); | 50 | set_irq_regs(old_regs); |
51 | } | 51 | } |
52 | 52 | ||
53 | void hv_setup_vmbus_irq(void (*handler)(void)) | 53 | void hv_setup_vmbus_irq(void (*handler)(void)) |
54 | { | 54 | { |
55 | vmbus_handler = handler; | 55 | vmbus_handler = handler; |
56 | /* | 56 | /* |
57 | * Setup the IDT for hypervisor callback. Prevent reallocation | 57 | * Setup the IDT for hypervisor callback. Prevent reallocation |
58 | * at module reload. | 58 | * at module reload. |
59 | */ | 59 | */ |
60 | if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) | 60 | if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) |
61 | alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, | 61 | alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, |
62 | hyperv_callback_vector); | 62 | hyperv_callback_vector); |
63 | } | 63 | } |
64 | 64 | ||
65 | void hv_remove_vmbus_irq(void) | 65 | void hv_remove_vmbus_irq(void) |
66 | { | 66 | { |
67 | /* We have no way to deallocate the interrupt gate */ | 67 | /* We have no way to deallocate the interrupt gate */ |
68 | vmbus_handler = NULL; | 68 | vmbus_handler = NULL; |
69 | } | 69 | } |
70 | EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq); | 70 | EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq); |
71 | EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq); | 71 | EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq); |
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | static uint32_t __init ms_hyperv_platform(void) | 74 | static uint32_t __init ms_hyperv_platform(void) |
75 | { | 75 | { |
76 | u32 eax; | 76 | u32 eax; |
77 | u32 hyp_signature[3]; | 77 | u32 hyp_signature[3]; |
78 | 78 | ||
79 | if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) | 79 | if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) |
80 | return 0; | 80 | return 0; |
81 | 81 | ||
82 | cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, | 82 | cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, |
83 | &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]); | 83 | &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]); |
84 | 84 | ||
85 | if (eax >= HYPERV_CPUID_MIN && | 85 | if (eax >= HYPERV_CPUID_MIN && |
86 | eax <= HYPERV_CPUID_MAX && | 86 | eax <= HYPERV_CPUID_MAX && |
87 | !memcmp("Microsoft Hv", hyp_signature, 12)) | 87 | !memcmp("Microsoft Hv", hyp_signature, 12)) |
88 | return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS; | 88 | return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS; |
89 | 89 | ||
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | static cycle_t read_hv_clock(struct clocksource *arg) | 93 | static cycle_t read_hv_clock(struct clocksource *arg) |
94 | { | 94 | { |
95 | cycle_t current_tick; | 95 | cycle_t current_tick; |
96 | /* | 96 | /* |
97 | * Read the partition counter to get the current tick count. This count | 97 | * Read the partition counter to get the current tick count. This count |
98 | * is set to 0 when the partition is created and is incremented in | 98 | * is set to 0 when the partition is created and is incremented in |
99 | * 100 nanosecond units. | 99 | * 100 nanosecond units. |
100 | */ | 100 | */ |
101 | rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); | 101 | rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); |
102 | return current_tick; | 102 | return current_tick; |
103 | } | 103 | } |
104 | 104 | ||
105 | static struct clocksource hyperv_cs = { | 105 | static struct clocksource hyperv_cs = { |
106 | .name = "hyperv_clocksource", | 106 | .name = "hyperv_clocksource", |
107 | .rating = 400, /* use this when running on Hyperv*/ | 107 | .rating = 400, /* use this when running on Hyperv*/ |
108 | .read = read_hv_clock, | 108 | .read = read_hv_clock, |
109 | .mask = CLOCKSOURCE_MASK(64), | 109 | .mask = CLOCKSOURCE_MASK(64), |
110 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
110 | }; | 111 | }; |
111 | 112 | ||
112 | static void __init ms_hyperv_init_platform(void) | 113 | static void __init ms_hyperv_init_platform(void) |
113 | { | 114 | { |
114 | /* | 115 | /* |
115 | * Extract the features and hints | 116 | * Extract the features and hints |
116 | */ | 117 | */ |
117 | ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES); | 118 | ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES); |
118 | ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); | 119 | ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); |
119 | 120 | ||
120 | printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n", | 121 | printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n", |
121 | ms_hyperv.features, ms_hyperv.hints); | 122 | ms_hyperv.features, ms_hyperv.hints); |
122 | 123 | ||
123 | #ifdef CONFIG_X86_LOCAL_APIC | 124 | #ifdef CONFIG_X86_LOCAL_APIC |
124 | if (ms_hyperv.features & HV_X64_MSR_APIC_FREQUENCY_AVAILABLE) { | 125 | if (ms_hyperv.features & HV_X64_MSR_APIC_FREQUENCY_AVAILABLE) { |
125 | /* | 126 | /* |
126 | * Get the APIC frequency. | 127 | * Get the APIC frequency. |
127 | */ | 128 | */ |
128 | u64 hv_lapic_frequency; | 129 | u64 hv_lapic_frequency; |
129 | 130 | ||
130 | rdmsrl(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency); | 131 | rdmsrl(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency); |
131 | hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ); | 132 | hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ); |
132 | lapic_timer_frequency = hv_lapic_frequency; | 133 | lapic_timer_frequency = hv_lapic_frequency; |
133 | printk(KERN_INFO "HyperV: LAPIC Timer Frequency: %#x\n", | 134 | printk(KERN_INFO "HyperV: LAPIC Timer Frequency: %#x\n", |
134 | lapic_timer_frequency); | 135 | lapic_timer_frequency); |
135 | } | 136 | } |
136 | #endif | 137 | #endif |
137 | 138 | ||
138 | if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) | 139 | if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) |
139 | clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); | 140 | clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); |
140 | 141 | ||
141 | #ifdef CONFIG_X86_IO_APIC | 142 | #ifdef CONFIG_X86_IO_APIC |
142 | no_timer_check = 1; | 143 | no_timer_check = 1; |
143 | #endif | 144 | #endif |
144 | 145 | ||
145 | } | 146 | } |
146 | 147 | ||
147 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { | 148 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { |
148 | .name = "Microsoft HyperV", | 149 | .name = "Microsoft HyperV", |
149 | .detect = ms_hyperv_platform, | 150 | .detect = ms_hyperv_platform, |
150 | .init_platform = ms_hyperv_init_platform, | 151 | .init_platform = ms_hyperv_init_platform, |
151 | }; | 152 | }; |
152 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); | 153 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); |
153 | 154 |