diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 14:38:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 14:38:22 -0500 |
commit | e30aee9e10bb5168579e047f05c3d13d09e23356 (patch) | |
tree | 12371bdcd52d2427cad838201997479e31b6a9c9 /arch/x86 | |
parent | 8ff546b801e5cca0337c0f0a7234795d0a6309a1 (diff) | |
parent | 6cf18e6927c0b224f972e3042fb85770d63cb9f8 (diff) |
Merge tag 'char-misc-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH:
"Here is the big char/misc driver patchset for 4.11-rc1.
Lots of different driver subsystems updated here: rework for the
hyperv subsystem to handle new platforms better, mei and w1 and extcon
driver updates, as well as a number of other "minor" driver updates.
All of these have been in linux-next for a while with no reported
issues"
* tag 'char-misc-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (169 commits)
goldfish: Sanitize the broken interrupt handler
x86/platform/goldfish: Prevent unconditional loading
vmbus: replace modulus operation with subtraction
vmbus: constify parameters where possible
vmbus: expose hv_begin/end_read
vmbus: remove conditional locking of vmbus_write
vmbus: add direct isr callback mode
vmbus: change to per channel tasklet
vmbus: put related per-cpu variable together
vmbus: callback is in softirq not workqueue
binder: Add support for file-descriptor arrays
binder: Add support for scatter-gather
binder: Add extra size to allocator
binder: Refactor binder_transact()
binder: Support multiple /dev instances
binder: Deal with contexts in debugfs
binder: Support multiple context managers
binder: Split flat_binder_object
auxdisplay: ht16k33: remove private workqueue
auxdisplay: ht16k33: rework input device initialization
...
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kbuild | 3 | ||||
-rw-r--r-- | arch/x86/hyperv/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/hyperv/hv_init.c | 277 | ||||
-rw-r--r-- | arch/x86/include/asm/mshyperv.h | 151 | ||||
-rw-r--r-- | arch/x86/include/uapi/asm/hyperv.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mshyperv.c | 50 | ||||
-rw-r--r-- | arch/x86/platform/goldfish/goldfish.c | 14 |
7 files changed, 480 insertions, 24 deletions
diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild index eb3abf8ac44e..586b786b3edf 100644 --- a/arch/x86/Kbuild +++ b/arch/x86/Kbuild | |||
@@ -7,6 +7,9 @@ obj-$(CONFIG_KVM) += kvm/ | |||
7 | # Xen paravirtualization support | 7 | # Xen paravirtualization support |
8 | obj-$(CONFIG_XEN) += xen/ | 8 | obj-$(CONFIG_XEN) += xen/ |
9 | 9 | ||
10 | # Hyper-V paravirtualization support | ||
11 | obj-$(CONFIG_HYPERVISOR_GUEST) += hyperv/ | ||
12 | |||
10 | # lguest paravirtualization support | 13 | # lguest paravirtualization support |
11 | obj-$(CONFIG_LGUEST_GUEST) += lguest/ | 14 | obj-$(CONFIG_LGUEST_GUEST) += lguest/ |
12 | 15 | ||
diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile new file mode 100644 index 000000000000..171ae09864d7 --- /dev/null +++ b/arch/x86/hyperv/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-y := hv_init.o | |||
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c new file mode 100644 index 000000000000..db64baf0e500 --- /dev/null +++ b/arch/x86/hyperv/hv_init.c | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * X86 specific Hyper-V initialization code. | ||
3 | * | ||
4 | * Copyright (C) 2016, Microsoft, Inc. | ||
5 | * | ||
6 | * Author : K. Y. Srinivasan <kys@microsoft.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published | ||
10 | * by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
15 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
16 | * details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <asm/hypervisor.h> | ||
22 | #include <asm/hyperv.h> | ||
23 | #include <asm/mshyperv.h> | ||
24 | #include <linux/version.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/clockchips.h> | ||
28 | |||
29 | |||
30 | #ifdef CONFIG_X86_64 | ||
31 | |||
32 | static struct ms_hyperv_tsc_page *tsc_pg; | ||
33 | |||
34 | static u64 read_hv_clock_tsc(struct clocksource *arg) | ||
35 | { | ||
36 | u64 current_tick; | ||
37 | |||
38 | if (tsc_pg->tsc_sequence != 0) { | ||
39 | /* | ||
40 | * Use the tsc page to compute the value. | ||
41 | */ | ||
42 | |||
43 | while (1) { | ||
44 | u64 tmp; | ||
45 | u32 sequence = tsc_pg->tsc_sequence; | ||
46 | u64 cur_tsc; | ||
47 | u64 scale = tsc_pg->tsc_scale; | ||
48 | s64 offset = tsc_pg->tsc_offset; | ||
49 | |||
50 | rdtscll(cur_tsc); | ||
51 | /* current_tick = ((cur_tsc *scale) >> 64) + offset */ | ||
52 | asm("mulq %3" | ||
53 | : "=d" (current_tick), "=a" (tmp) | ||
54 | : "a" (cur_tsc), "r" (scale)); | ||
55 | |||
56 | current_tick += offset; | ||
57 | if (tsc_pg->tsc_sequence == sequence) | ||
58 | return current_tick; | ||
59 | |||
60 | if (tsc_pg->tsc_sequence != 0) | ||
61 | continue; | ||
62 | /* | ||
63 | * Fallback using MSR method. | ||
64 | */ | ||
65 | break; | ||
66 | } | ||
67 | } | ||
68 | rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); | ||
69 | return current_tick; | ||
70 | } | ||
71 | |||
72 | static struct clocksource hyperv_cs_tsc = { | ||
73 | .name = "hyperv_clocksource_tsc_page", | ||
74 | .rating = 400, | ||
75 | .read = read_hv_clock_tsc, | ||
76 | .mask = CLOCKSOURCE_MASK(64), | ||
77 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
78 | }; | ||
79 | #endif | ||
80 | |||
81 | static u64 read_hv_clock_msr(struct clocksource *arg) | ||
82 | { | ||
83 | u64 current_tick; | ||
84 | /* | ||
85 | * Read the partition counter to get the current tick count. This count | ||
86 | * is set to 0 when the partition is created and is incremented in | ||
87 | * 100 nanosecond units. | ||
88 | */ | ||
89 | rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); | ||
90 | return current_tick; | ||
91 | } | ||
92 | |||
93 | static struct clocksource hyperv_cs_msr = { | ||
94 | .name = "hyperv_clocksource_msr", | ||
95 | .rating = 400, | ||
96 | .read = read_hv_clock_msr, | ||
97 | .mask = CLOCKSOURCE_MASK(64), | ||
98 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
99 | }; | ||
100 | |||
101 | static void *hypercall_pg; | ||
102 | struct clocksource *hyperv_cs; | ||
103 | EXPORT_SYMBOL_GPL(hyperv_cs); | ||
104 | |||
105 | /* | ||
106 | * This function is to be invoked early in the boot sequence after the | ||
107 | * hypervisor has been detected. | ||
108 | * | ||
109 | * 1. Setup the hypercall page. | ||
110 | * 2. Register Hyper-V specific clocksource. | ||
111 | */ | ||
112 | void hyperv_init(void) | ||
113 | { | ||
114 | u64 guest_id; | ||
115 | union hv_x64_msr_hypercall_contents hypercall_msr; | ||
116 | |||
117 | if (x86_hyper != &x86_hyper_ms_hyperv) | ||
118 | return; | ||
119 | |||
120 | /* | ||
121 | * Setup the hypercall page and enable hypercalls. | ||
122 | * 1. Register the guest ID | ||
123 | * 2. Enable the hypercall and register the hypercall page | ||
124 | */ | ||
125 | guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); | ||
126 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); | ||
127 | |||
128 | hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX); | ||
129 | if (hypercall_pg == NULL) { | ||
130 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | ||
135 | hypercall_msr.enable = 1; | ||
136 | hypercall_msr.guest_physical_address = vmalloc_to_pfn(hypercall_pg); | ||
137 | wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | ||
138 | |||
139 | /* | ||
140 | * Register Hyper-V specific clocksource. | ||
141 | */ | ||
142 | #ifdef CONFIG_X86_64 | ||
143 | if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) { | ||
144 | union hv_x64_msr_hypercall_contents tsc_msr; | ||
145 | |||
146 | tsc_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL); | ||
147 | if (!tsc_pg) | ||
148 | goto register_msr_cs; | ||
149 | |||
150 | hyperv_cs = &hyperv_cs_tsc; | ||
151 | |||
152 | rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64); | ||
153 | |||
154 | tsc_msr.enable = 1; | ||
155 | tsc_msr.guest_physical_address = vmalloc_to_pfn(tsc_pg); | ||
156 | |||
157 | wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64); | ||
158 | clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); | ||
159 | return; | ||
160 | } | ||
161 | #endif | ||
162 | /* | ||
163 | * For 32 bit guests just use the MSR based mechanism for reading | ||
164 | * the partition counter. | ||
165 | */ | ||
166 | |||
167 | register_msr_cs: | ||
168 | hyperv_cs = &hyperv_cs_msr; | ||
169 | if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) | ||
170 | clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * This routine is called before kexec/kdump, it does the required cleanup. | ||
175 | */ | ||
176 | void hyperv_cleanup(void) | ||
177 | { | ||
178 | union hv_x64_msr_hypercall_contents hypercall_msr; | ||
179 | |||
180 | /* Reset our OS id */ | ||
181 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0); | ||
182 | |||
183 | /* Reset the hypercall page */ | ||
184 | hypercall_msr.as_uint64 = 0; | ||
185 | wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | ||
186 | |||
187 | /* Reset the TSC page */ | ||
188 | hypercall_msr.as_uint64 = 0; | ||
189 | wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); | ||
190 | } | ||
191 | EXPORT_SYMBOL_GPL(hyperv_cleanup); | ||
192 | |||
193 | /* | ||
194 | * hv_do_hypercall- Invoke the specified hypercall | ||
195 | */ | ||
196 | u64 hv_do_hypercall(u64 control, void *input, void *output) | ||
197 | { | ||
198 | u64 input_address = (input) ? virt_to_phys(input) : 0; | ||
199 | u64 output_address = (output) ? virt_to_phys(output) : 0; | ||
200 | #ifdef CONFIG_X86_64 | ||
201 | u64 hv_status = 0; | ||
202 | |||
203 | if (!hypercall_pg) | ||
204 | return (u64)ULLONG_MAX; | ||
205 | |||
206 | __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8"); | ||
207 | __asm__ __volatile__("call *%3" : "=a" (hv_status) : | ||
208 | "c" (control), "d" (input_address), | ||
209 | "m" (hypercall_pg)); | ||
210 | |||
211 | return hv_status; | ||
212 | |||
213 | #else | ||
214 | |||
215 | u32 control_hi = control >> 32; | ||
216 | u32 control_lo = control & 0xFFFFFFFF; | ||
217 | u32 hv_status_hi = 1; | ||
218 | u32 hv_status_lo = 1; | ||
219 | u32 input_address_hi = input_address >> 32; | ||
220 | u32 input_address_lo = input_address & 0xFFFFFFFF; | ||
221 | u32 output_address_hi = output_address >> 32; | ||
222 | u32 output_address_lo = output_address & 0xFFFFFFFF; | ||
223 | |||
224 | if (!hypercall_pg) | ||
225 | return (u64)ULLONG_MAX; | ||
226 | |||
227 | __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi), | ||
228 | "=a"(hv_status_lo) : "d" (control_hi), | ||
229 | "a" (control_lo), "b" (input_address_hi), | ||
230 | "c" (input_address_lo), "D"(output_address_hi), | ||
231 | "S"(output_address_lo), "m" (hypercall_pg)); | ||
232 | |||
233 | return hv_status_lo | ((u64)hv_status_hi << 32); | ||
234 | #endif /* !x86_64 */ | ||
235 | } | ||
236 | EXPORT_SYMBOL_GPL(hv_do_hypercall); | ||
237 | |||
238 | void hyperv_report_panic(struct pt_regs *regs) | ||
239 | { | ||
240 | static bool panic_reported; | ||
241 | |||
242 | /* | ||
243 | * We prefer to report panic on 'die' chain as we have proper | ||
244 | * registers to report, but if we miss it (e.g. on BUG()) we need | ||
245 | * to report it on 'panic'. | ||
246 | */ | ||
247 | if (panic_reported) | ||
248 | return; | ||
249 | panic_reported = true; | ||
250 | |||
251 | wrmsrl(HV_X64_MSR_CRASH_P0, regs->ip); | ||
252 | wrmsrl(HV_X64_MSR_CRASH_P1, regs->ax); | ||
253 | wrmsrl(HV_X64_MSR_CRASH_P2, regs->bx); | ||
254 | wrmsrl(HV_X64_MSR_CRASH_P3, regs->cx); | ||
255 | wrmsrl(HV_X64_MSR_CRASH_P4, regs->dx); | ||
256 | |||
257 | /* | ||
258 | * Let Hyper-V know there is crash data available | ||
259 | */ | ||
260 | wrmsrl(HV_X64_MSR_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY); | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(hyperv_report_panic); | ||
263 | |||
264 | bool hv_is_hypercall_page_setup(void) | ||
265 | { | ||
266 | union hv_x64_msr_hypercall_contents hypercall_msr; | ||
267 | |||
268 | /* Check if the hypercall page is setup */ | ||
269 | hypercall_msr.as_uint64 = 0; | ||
270 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | ||
271 | |||
272 | if (!hypercall_msr.enable) | ||
273 | return false; | ||
274 | |||
275 | return true; | ||
276 | } | ||
277 | EXPORT_SYMBOL_GPL(hv_is_hypercall_page_setup); | ||
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index aaf59b7da98a..7c9c895432a9 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h | |||
@@ -3,8 +3,28 @@ | |||
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/interrupt.h> | 5 | #include <linux/interrupt.h> |
6 | #include <linux/clocksource.h> | ||
6 | #include <asm/hyperv.h> | 7 | #include <asm/hyperv.h> |
7 | 8 | ||
9 | /* | ||
10 | * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent | ||
11 | * is set by CPUID(HVCPUID_VERSION_FEATURES). | ||
12 | */ | ||
13 | enum hv_cpuid_function { | ||
14 | HVCPUID_VERSION_FEATURES = 0x00000001, | ||
15 | HVCPUID_VENDOR_MAXFUNCTION = 0x40000000, | ||
16 | HVCPUID_INTERFACE = 0x40000001, | ||
17 | |||
18 | /* | ||
19 | * The remaining functions depend on the value of | ||
20 | * HVCPUID_INTERFACE | ||
21 | */ | ||
22 | HVCPUID_VERSION = 0x40000002, | ||
23 | HVCPUID_FEATURES = 0x40000003, | ||
24 | HVCPUID_ENLIGHTENMENT_INFO = 0x40000004, | ||
25 | HVCPUID_IMPLEMENTATION_LIMITS = 0x40000005, | ||
26 | }; | ||
27 | |||
8 | struct ms_hyperv_info { | 28 | struct ms_hyperv_info { |
9 | u32 features; | 29 | u32 features; |
10 | u32 misc_features; | 30 | u32 misc_features; |
@@ -13,6 +33,128 @@ struct ms_hyperv_info { | |||
13 | 33 | ||
14 | extern struct ms_hyperv_info ms_hyperv; | 34 | extern struct ms_hyperv_info ms_hyperv; |
15 | 35 | ||
36 | /* | ||
37 | * Declare the MSR used to setup pages used to communicate with the hypervisor. | ||
38 | */ | ||
39 | union hv_x64_msr_hypercall_contents { | ||
40 | u64 as_uint64; | ||
41 | struct { | ||
42 | u64 enable:1; | ||
43 | u64 reserved:11; | ||
44 | u64 guest_physical_address:52; | ||
45 | }; | ||
46 | }; | ||
47 | |||
48 | /* | ||
49 | * TSC page layout. | ||
50 | */ | ||
51 | |||
52 | struct ms_hyperv_tsc_page { | ||
53 | volatile u32 tsc_sequence; | ||
54 | u32 reserved1; | ||
55 | volatile u64 tsc_scale; | ||
56 | volatile s64 tsc_offset; | ||
57 | u64 reserved2[509]; | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * The guest OS needs to register the guest ID with the hypervisor. | ||
62 | * The guest ID is a 64 bit entity and the structure of this ID is | ||
63 | * specified in the Hyper-V specification: | ||
64 | * | ||
65 | * msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx | ||
66 | * | ||
67 | * While the current guideline does not specify how Linux guest ID(s) | ||
68 | * need to be generated, our plan is to publish the guidelines for | ||
69 | * Linux and other guest operating systems that currently are hosted | ||
70 | * on Hyper-V. The implementation here conforms to this yet | ||
71 | * unpublished guidelines. | ||
72 | * | ||
73 | * | ||
74 | * Bit(s) | ||
75 | * 63 - Indicates if the OS is Open Source or not; 1 is Open Source | ||
76 | * 62:56 - Os Type; Linux is 0x100 | ||
77 | * 55:48 - Distro specific identification | ||
78 | * 47:16 - Linux kernel version number | ||
79 | * 15:0 - Distro specific identification | ||
80 | * | ||
81 | * | ||
82 | */ | ||
83 | |||
84 | #define HV_LINUX_VENDOR_ID 0x8100 | ||
85 | |||
86 | /* | ||
87 | * Generate the guest ID based on the guideline described above. | ||
88 | */ | ||
89 | |||
90 | static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, | ||
91 | __u64 d_info2) | ||
92 | { | ||
93 | __u64 guest_id = 0; | ||
94 | |||
95 | guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); | ||
96 | guest_id |= (d_info1 << 48); | ||
97 | guest_id |= (kernel_version << 16); | ||
98 | guest_id |= d_info2; | ||
99 | |||
100 | return guest_id; | ||
101 | } | ||
102 | |||
103 | |||
104 | /* Free the message slot and signal end-of-message if required */ | ||
105 | static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) | ||
106 | { | ||
107 | /* | ||
108 | * On crash we're reading some other CPU's message page and we need | ||
109 | * to be careful: this other CPU may already had cleared the header | ||
110 | * and the host may already had delivered some other message there. | ||
111 | * In case we blindly write msg->header.message_type we're going | ||
112 | * to lose it. We can still lose a message of the same type but | ||
113 | * we count on the fact that there can only be one | ||
114 | * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages | ||
115 | * on crash. | ||
116 | */ | ||
117 | if (cmpxchg(&msg->header.message_type, old_msg_type, | ||
118 | HVMSG_NONE) != old_msg_type) | ||
119 | return; | ||
120 | |||
121 | /* | ||
122 | * Make sure the write to MessageType (ie set to | ||
123 | * HVMSG_NONE) happens before we read the | ||
124 | * MessagePending and EOMing. Otherwise, the EOMing | ||
125 | * will not deliver any more messages since there is | ||
126 | * no empty slot | ||
127 | */ | ||
128 | mb(); | ||
129 | |||
130 | if (msg->header.message_flags.msg_pending) { | ||
131 | /* | ||
132 | * This will cause message queue rescan to | ||
133 | * possibly deliver another msg from the | ||
134 | * hypervisor | ||
135 | */ | ||
136 | wrmsrl(HV_X64_MSR_EOM, 0); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | #define hv_get_current_tick(tick) rdmsrl(HV_X64_MSR_TIME_REF_COUNT, tick) | ||
141 | #define hv_init_timer(timer, tick) wrmsrl(timer, tick) | ||
142 | #define hv_init_timer_config(config, val) wrmsrl(config, val) | ||
143 | |||
144 | #define hv_get_simp(val) rdmsrl(HV_X64_MSR_SIMP, val) | ||
145 | #define hv_set_simp(val) wrmsrl(HV_X64_MSR_SIMP, val) | ||
146 | |||
147 | #define hv_get_siefp(val) rdmsrl(HV_X64_MSR_SIEFP, val) | ||
148 | #define hv_set_siefp(val) wrmsrl(HV_X64_MSR_SIEFP, val) | ||
149 | |||
150 | #define hv_get_synic_state(val) rdmsrl(HV_X64_MSR_SCONTROL, val) | ||
151 | #define hv_set_synic_state(val) wrmsrl(HV_X64_MSR_SCONTROL, val) | ||
152 | |||
153 | #define hv_get_vp_index(index) rdmsrl(HV_X64_MSR_VP_INDEX, index) | ||
154 | |||
155 | #define hv_get_synint_state(int_num, val) rdmsrl(int_num, val) | ||
156 | #define hv_set_synint_state(int_num, val) wrmsrl(int_num, val) | ||
157 | |||
16 | void hyperv_callback_vector(void); | 158 | void hyperv_callback_vector(void); |
17 | #ifdef CONFIG_TRACING | 159 | #ifdef CONFIG_TRACING |
18 | #define trace_hyperv_callback_vector hyperv_callback_vector | 160 | #define trace_hyperv_callback_vector hyperv_callback_vector |
@@ -25,4 +167,13 @@ void hv_setup_kexec_handler(void (*handler)(void)); | |||
25 | void hv_remove_kexec_handler(void); | 167 | void hv_remove_kexec_handler(void); |
26 | void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); | 168 | void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); |
27 | void hv_remove_crash_handler(void); | 169 | void hv_remove_crash_handler(void); |
170 | |||
171 | #if IS_ENABLED(CONFIG_HYPERV) | ||
172 | extern struct clocksource *hyperv_cs; | ||
173 | |||
174 | void hyperv_init(void); | ||
175 | void hyperv_report_panic(struct pt_regs *regs); | ||
176 | bool hv_is_hypercall_page_setup(void); | ||
177 | void hyperv_cleanup(void); | ||
178 | #endif | ||
28 | #endif | 179 | #endif |
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 9b1a91834ac8..3a20ccf787b8 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h | |||
@@ -73,6 +73,9 @@ | |||
73 | */ | 73 | */ |
74 | #define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8) | 74 | #define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8) |
75 | 75 | ||
76 | /* Crash MSR available */ | ||
77 | #define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10) | ||
78 | |||
76 | /* | 79 | /* |
77 | * Feature identification: EBX indicates which flags were specified at | 80 | * Feature identification: EBX indicates which flags were specified at |
78 | * partition creation. The format is the same as the partition creation | 81 | * partition creation. The format is the same as the partition creation |
@@ -144,6 +147,11 @@ | |||
144 | */ | 147 | */ |
145 | #define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) | 148 | #define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) |
146 | 149 | ||
150 | /* | ||
151 | * Crash notification flag. | ||
152 | */ | ||
153 | #define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63) | ||
154 | |||
147 | /* MSR used to identify the guest OS. */ | 155 | /* MSR used to identify the guest OS. */ |
148 | #define HV_X64_MSR_GUEST_OS_ID 0x40000000 | 156 | #define HV_X64_MSR_GUEST_OS_ID 0x40000000 |
149 | 157 | ||
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 65e20c97e04b..b5375b9497b3 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c | |||
@@ -133,26 +133,6 @@ static uint32_t __init ms_hyperv_platform(void) | |||
133 | return 0; | 133 | return 0; |
134 | } | 134 | } |
135 | 135 | ||
136 | static u64 read_hv_clock(struct clocksource *arg) | ||
137 | { | ||
138 | u64 current_tick; | ||
139 | /* | ||
140 | * Read the partition counter to get the current tick count. This count | ||
141 | * is set to 0 when the partition is created and is incremented in | ||
142 | * 100 nanosecond units. | ||
143 | */ | ||
144 | rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); | ||
145 | return current_tick; | ||
146 | } | ||
147 | |||
148 | static struct clocksource hyperv_cs = { | ||
149 | .name = "hyperv_clocksource", | ||
150 | .rating = 400, /* use this when running on Hyperv*/ | ||
151 | .read = read_hv_clock, | ||
152 | .mask = CLOCKSOURCE_MASK(64), | ||
153 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
154 | }; | ||
155 | |||
156 | static unsigned char hv_get_nmi_reason(void) | 136 | static unsigned char hv_get_nmi_reason(void) |
157 | { | 137 | { |
158 | return 0; | 138 | return 0; |
@@ -180,6 +160,11 @@ static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs) | |||
180 | 160 | ||
181 | static void __init ms_hyperv_init_platform(void) | 161 | static void __init ms_hyperv_init_platform(void) |
182 | { | 162 | { |
163 | int hv_host_info_eax; | ||
164 | int hv_host_info_ebx; | ||
165 | int hv_host_info_ecx; | ||
166 | int hv_host_info_edx; | ||
167 | |||
183 | /* | 168 | /* |
184 | * Extract the features and hints | 169 | * Extract the features and hints |
185 | */ | 170 | */ |
@@ -190,6 +175,21 @@ static void __init ms_hyperv_init_platform(void) | |||
190 | pr_info("HyperV: features 0x%x, hints 0x%x\n", | 175 | pr_info("HyperV: features 0x%x, hints 0x%x\n", |
191 | ms_hyperv.features, ms_hyperv.hints); | 176 | ms_hyperv.features, ms_hyperv.hints); |
192 | 177 | ||
178 | /* | ||
179 | * Extract host information. | ||
180 | */ | ||
181 | if (cpuid_eax(HVCPUID_VENDOR_MAXFUNCTION) >= HVCPUID_VERSION) { | ||
182 | hv_host_info_eax = cpuid_eax(HVCPUID_VERSION); | ||
183 | hv_host_info_ebx = cpuid_ebx(HVCPUID_VERSION); | ||
184 | hv_host_info_ecx = cpuid_ecx(HVCPUID_VERSION); | ||
185 | hv_host_info_edx = cpuid_edx(HVCPUID_VERSION); | ||
186 | |||
187 | pr_info("Hyper-V Host Build:%d-%d.%d-%d-%d.%d\n", | ||
188 | hv_host_info_eax, hv_host_info_ebx >> 16, | ||
189 | hv_host_info_ebx & 0xFFFF, hv_host_info_ecx, | ||
190 | hv_host_info_edx >> 24, hv_host_info_edx & 0xFFFFFF); | ||
191 | } | ||
192 | |||
193 | #ifdef CONFIG_X86_LOCAL_APIC | 193 | #ifdef CONFIG_X86_LOCAL_APIC |
194 | if (ms_hyperv.features & HV_X64_MSR_APIC_FREQUENCY_AVAILABLE) { | 194 | if (ms_hyperv.features & HV_X64_MSR_APIC_FREQUENCY_AVAILABLE) { |
195 | /* | 195 | /* |
@@ -208,9 +208,6 @@ static void __init ms_hyperv_init_platform(void) | |||
208 | "hv_nmi_unknown"); | 208 | "hv_nmi_unknown"); |
209 | #endif | 209 | #endif |
210 | 210 | ||
211 | if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) | ||
212 | clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); | ||
213 | |||
214 | #ifdef CONFIG_X86_IO_APIC | 211 | #ifdef CONFIG_X86_IO_APIC |
215 | no_timer_check = 1; | 212 | no_timer_check = 1; |
216 | #endif | 213 | #endif |
@@ -227,6 +224,13 @@ static void __init ms_hyperv_init_platform(void) | |||
227 | */ | 224 | */ |
228 | if (efi_enabled(EFI_BOOT)) | 225 | if (efi_enabled(EFI_BOOT)) |
229 | x86_platform.get_nmi_reason = hv_get_nmi_reason; | 226 | x86_platform.get_nmi_reason = hv_get_nmi_reason; |
227 | |||
228 | #if IS_ENABLED(CONFIG_HYPERV) | ||
229 | /* | ||
230 | * Setup the hook to get control post apic initialization. | ||
231 | */ | ||
232 | x86_platform.apic_post_init = hyperv_init; | ||
233 | #endif | ||
230 | } | 234 | } |
231 | 235 | ||
232 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { | 236 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { |
diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c index 1693107a518e..0d17c0aafeb1 100644 --- a/arch/x86/platform/goldfish/goldfish.c +++ b/arch/x86/platform/goldfish/goldfish.c | |||
@@ -42,10 +42,22 @@ static struct resource goldfish_pdev_bus_resources[] = { | |||
42 | } | 42 | } |
43 | }; | 43 | }; |
44 | 44 | ||
45 | static bool goldfish_enable __initdata; | ||
46 | |||
47 | static int __init goldfish_setup(char *str) | ||
48 | { | ||
49 | goldfish_enable = true; | ||
50 | return 0; | ||
51 | } | ||
52 | __setup("goldfish", goldfish_setup); | ||
53 | |||
45 | static int __init goldfish_init(void) | 54 | static int __init goldfish_init(void) |
46 | { | 55 | { |
56 | if (!goldfish_enable) | ||
57 | return -ENODEV; | ||
58 | |||
47 | platform_device_register_simple("goldfish_pdev_bus", -1, | 59 | platform_device_register_simple("goldfish_pdev_bus", -1, |
48 | goldfish_pdev_bus_resources, 2); | 60 | goldfish_pdev_bus_resources, 2); |
49 | return 0; | 61 | return 0; |
50 | } | 62 | } |
51 | device_initcall(goldfish_init); | 63 | device_initcall(goldfish_init); |