diff options
author | K. Y. Srinivasan <kys@microsoft.com> | 2018-05-16 17:53:30 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-05-19 07:23:17 -0400 |
commit | 6b48cb5f8347bc0153ff1d7b075db92e6723ffdb (patch) | |
tree | c6d6df00b59669cc6040ff7981f4216af6925e26 | |
parent | 73fcb1a370c76b202d406e95d9dabb76eaccf484 (diff) |
X86/Hyper-V: Enlighten APIC access
Hyper-V supports MSR based APIC access; implement
the enlightenment.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Cc: olaf@aepfle.de
Cc: sthemmin@microsoft.com
Cc: gregkh@linuxfoundation.org
Cc: jasowang@redhat.com
Cc: Michael.H.Kelley@microsoft.com
Cc: hpa@zytor.com
Cc: apw@canonical.com
Cc: devel@linuxdriverproject.org
Cc: vkuznets@redhat.com
Link: https://lkml.kernel.org/r/20180516215334.6547-1-kys@linuxonhyperv.com
-rw-r--r-- | arch/x86/hyperv/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/hyperv/hv_apic.c | 104 | ||||
-rw-r--r-- | arch/x86/hyperv/hv_init.c | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/mshyperv.h | 4 |
4 files changed, 112 insertions, 3 deletions
diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile index 367a8203cfcf..00ce4df01a09 100644 --- a/arch/x86/hyperv/Makefile +++ b/arch/x86/hyperv/Makefile | |||
@@ -1 +1 @@ | |||
obj-y := hv_init.o mmu.o | obj-y := hv_init.o mmu.o hv_apic.o | ||
diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c new file mode 100644 index 000000000000..ca20e31d311c --- /dev/null +++ b/arch/x86/hyperv/hv_apic.c | |||
@@ -0,0 +1,104 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | /* | ||
4 | * Hyper-V specific APIC code. | ||
5 | * | ||
6 | * Copyright (C) 2018, Microsoft, Inc. | ||
7 | * | ||
8 | * Author : K. Y. Srinivasan <kys@microsoft.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published | ||
12 | * by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
17 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
18 | * details. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/version.h> | ||
24 | #include <linux/vmalloc.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/clockchips.h> | ||
27 | #include <linux/hyperv.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/cpuhotplug.h> | ||
30 | #include <asm/hypervisor.h> | ||
31 | #include <asm/mshyperv.h> | ||
32 | |||
33 | #ifdef CONFIG_X86_64 | ||
34 | #if IS_ENABLED(CONFIG_HYPERV) | ||
35 | |||
36 | static u64 hv_apic_icr_read(void) | ||
37 | { | ||
38 | u64 reg_val; | ||
39 | |||
40 | rdmsrl(HV_X64_MSR_ICR, reg_val); | ||
41 | return reg_val; | ||
42 | } | ||
43 | |||
44 | static void hv_apic_icr_write(u32 low, u32 id) | ||
45 | { | ||
46 | u64 reg_val; | ||
47 | |||
48 | reg_val = SET_APIC_DEST_FIELD(id); | ||
49 | reg_val = reg_val << 32; | ||
50 | reg_val |= low; | ||
51 | |||
52 | wrmsrl(HV_X64_MSR_ICR, reg_val); | ||
53 | } | ||
54 | |||
55 | static u32 hv_apic_read(u32 reg) | ||
56 | { | ||
57 | u32 reg_val, hi; | ||
58 | |||
59 | switch (reg) { | ||
60 | case APIC_EOI: | ||
61 | rdmsr(HV_X64_MSR_EOI, reg_val, hi); | ||
62 | return reg_val; | ||
63 | case APIC_TASKPRI: | ||
64 | rdmsr(HV_X64_MSR_TPR, reg_val, hi); | ||
65 | return reg_val; | ||
66 | |||
67 | default: | ||
68 | return native_apic_mem_read(reg); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static void hv_apic_write(u32 reg, u32 val) | ||
73 | { | ||
74 | switch (reg) { | ||
75 | case APIC_EOI: | ||
76 | wrmsr(HV_X64_MSR_EOI, val, 0); | ||
77 | break; | ||
78 | case APIC_TASKPRI: | ||
79 | wrmsr(HV_X64_MSR_TPR, val, 0); | ||
80 | break; | ||
81 | default: | ||
82 | native_apic_mem_write(reg, val); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static void hv_apic_eoi_write(u32 reg, u32 val) | ||
87 | { | ||
88 | wrmsr(HV_X64_MSR_EOI, val, 0); | ||
89 | } | ||
90 | |||
91 | void __init hv_apic_init(void) | ||
92 | { | ||
93 | if (ms_hyperv.hints & HV_X64_APIC_ACCESS_RECOMMENDED) { | ||
94 | pr_info("Hyper-V: Using MSR based APIC access\n"); | ||
95 | apic_set_eoi_write(hv_apic_eoi_write); | ||
96 | apic->read = hv_apic_read; | ||
97 | apic->write = hv_apic_write; | ||
98 | apic->icr_write = hv_apic_icr_write; | ||
99 | apic->icr_read = hv_apic_icr_read; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | #endif /* CONFIG_HYPERV */ | ||
104 | #endif /* CONFIG_X86_64 */ | ||
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index cfecc2272f2d..71e50fc2b7ef 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c | |||
@@ -242,8 +242,9 @@ static int hv_cpu_die(unsigned int cpu) | |||
242 | * | 242 | * |
243 | * 1. Setup the hypercall page. | 243 | * 1. Setup the hypercall page. |
244 | * 2. Register Hyper-V specific clocksource. | 244 | * 2. Register Hyper-V specific clocksource. |
245 | * 3. Setup Hyper-V specific APIC entry points. | ||
245 | */ | 246 | */ |
246 | void hyperv_init(void) | 247 | void __init hyperv_init(void) |
247 | { | 248 | { |
248 | u64 guest_id, required_msrs; | 249 | u64 guest_id, required_msrs; |
249 | union hv_x64_msr_hypercall_contents hypercall_msr; | 250 | union hv_x64_msr_hypercall_contents hypercall_msr; |
@@ -298,6 +299,8 @@ void hyperv_init(void) | |||
298 | 299 | ||
299 | hyper_alloc_mmu(); | 300 | hyper_alloc_mmu(); |
300 | 301 | ||
302 | hv_apic_init(); | ||
303 | |||
301 | /* | 304 | /* |
302 | * Register Hyper-V specific clocksource. | 305 | * Register Hyper-V specific clocksource. |
303 | */ | 306 | */ |
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index b90e79610cf7..162977b82e2e 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h | |||
@@ -258,7 +258,7 @@ static inline int hv_cpu_number_to_vp_number(int cpu_number) | |||
258 | return hv_vp_index[cpu_number]; | 258 | return hv_vp_index[cpu_number]; |
259 | } | 259 | } |
260 | 260 | ||
261 | void hyperv_init(void); | 261 | void __init hyperv_init(void); |
262 | void hyperv_setup_mmu_ops(void); | 262 | void hyperv_setup_mmu_ops(void); |
263 | void hyper_alloc_mmu(void); | 263 | void hyper_alloc_mmu(void); |
264 | void hyperv_report_panic(struct pt_regs *regs, long err); | 264 | void hyperv_report_panic(struct pt_regs *regs, long err); |
@@ -269,6 +269,7 @@ void hyperv_reenlightenment_intr(struct pt_regs *regs); | |||
269 | void set_hv_tscchange_cb(void (*cb)(void)); | 269 | void set_hv_tscchange_cb(void (*cb)(void)); |
270 | void clear_hv_tscchange_cb(void); | 270 | void clear_hv_tscchange_cb(void); |
271 | void hyperv_stop_tsc_emulation(void); | 271 | void hyperv_stop_tsc_emulation(void); |
272 | void hv_apic_init(void); | ||
272 | #else /* CONFIG_HYPERV */ | 273 | #else /* CONFIG_HYPERV */ |
273 | static inline void hyperv_init(void) {} | 274 | static inline void hyperv_init(void) {} |
274 | static inline bool hv_is_hyperv_initialized(void) { return false; } | 275 | static inline bool hv_is_hyperv_initialized(void) { return false; } |
@@ -277,6 +278,7 @@ static inline void hyperv_setup_mmu_ops(void) {} | |||
277 | static inline void set_hv_tscchange_cb(void (*cb)(void)) {} | 278 | static inline void set_hv_tscchange_cb(void (*cb)(void)) {} |
278 | static inline void clear_hv_tscchange_cb(void) {} | 279 | static inline void clear_hv_tscchange_cb(void) {} |
279 | static inline void hyperv_stop_tsc_emulation(void) {}; | 280 | static inline void hyperv_stop_tsc_emulation(void) {}; |
281 | static inline void hv_apic_init(void) {} | ||
280 | static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu) | 282 | static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu) |
281 | { | 283 | { |
282 | return NULL; | 284 | return NULL; |