@@ -134,26 +134,6 @@ static uint32_t __init ms_hyperv_platform(void)
return 0;
}
-static cycle_t read_hv_clock(struct clocksource *arg)
-{
- cycle_t current_tick;
- /*
- * Read the partition counter to get the current tick count. This count
- * is set to 0 when the partition is created and is incremented in
- * 100 nanosecond units.
- */
- rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
- return current_tick;
-}
-
-static struct clocksource hyperv_cs = {
- .name = "hyperv_clocksource",
- .rating = 400, /* use this when running on Hyperv*/
- .read = read_hv_clock,
- .mask = CLOCKSOURCE_MASK(64),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static unsigned char hv_get_nmi_reason(void)
{
return 0;
@@ -209,9 +189,6 @@ static void __init ms_hyperv_init_platform(void)
"hv_nmi_unknown");
#endif
- if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
- clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
-
#ifdef CONFIG_X86_IO_APIC
no_timer_check = 1;
#endif
@@ -191,6 +191,28 @@ static struct clocksource hyperv_cs_tsc = {
};
#endif
+static cycle_t read_hv_clock_msr(struct clocksource *arg)
+{
+ cycle_t current_tick;
+ /*
+ * Read the partition counter to get the current tick count. This count
+ * is set to 0 when the partition is created and is incremented in
+ * 100 nanosecond units.
+ */
+ rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+ return current_tick;
+}
+
+static struct clocksource hyperv_cs_msr = {
+ .name = "hyperv_clocksource_msr",
+ .rating = 400, /* use this when running on Hyperv*/
+ .read = read_hv_clock_msr,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+struct clocksource *hyperv_cs;
+EXPORT_SYMBOL_GPL(hyperv_cs);
/*
* hv_init - Main initialization routine.
@@ -254,9 +276,11 @@ int hv_init(void)
va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (!va_tsc)
- goto cleanup;
+ goto register_msr_cs;
hv_context.tsc_page = va_tsc;
+ hyperv_cs = &hyperv_cs_tsc;
+
rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
tsc_msr.enable = 1;
@@ -266,6 +290,16 @@ int hv_init(void)
clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
}
#endif
+ /*
+ * For 32 bit guests just use the MSR based mechanism for reading
+ * the partition counter.
+ */
+
+register_msr_cs:
+ hyperv_cs = &hyperv_cs_msr;
+ if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
+ clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
+
return 0;
cleanup:
@@ -29,6 +29,7 @@
#include <asm/sync_bitops.h>
#include <linux/atomic.h>
#include <linux/hyperv.h>
+#include <linux/clocksource.h>
/*
* Timeout for services such as KVP and fcopy.
@@ -719,4 +720,6 @@ enum hvutil_device_state {
HVUTIL_DEVICE_DYING, /* driver unload is in progress */
};
+extern struct clocksource *hyperv_cs;
+
#endif /* _HYPERV_VMBUS_H */
BugLink: http://bugs.launchpad.net/bugs/1676635 Make the MSR and TSC clock sources available during the hv_init() and export them via hyperv_cs in a similar way as the following upstream commit does: commit dee863b571b0 ("hv: export current Hyper-V clocksource") Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> --- arch/x86/kernel/cpu/mshyperv.c | 23 ----------------------- drivers/hv/hv.c | 36 +++++++++++++++++++++++++++++++++++- drivers/hv/hyperv_vmbus.h | 3 +++ 3 files changed, 38 insertions(+), 24 deletions(-)