forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-11 297b60346df8beafee954a0fd7c2d64f33f3b9bc
kernel/arch/x86/kernel/cpu/mshyperv.c
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * HyperV Detection code.
34 *
45 * Copyright (C) 2010, Novell, Inc.
56 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
6
- *
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
9
- * the Free Software Foundation; version 2 of the License.
10
- *
117 */
128
139 #include <linux/types.h>
....@@ -21,17 +17,20 @@
2117 #include <linux/irq.h>
2218 #include <linux/kexec.h>
2319 #include <linux/i8253.h>
20
+#include <linux/random.h>
2421 #include <asm/processor.h>
2522 #include <asm/hypervisor.h>
2623 #include <asm/hyperv-tlfs.h>
2724 #include <asm/mshyperv.h>
2825 #include <asm/desc.h>
26
+#include <asm/idtentry.h>
2927 #include <asm/irq_regs.h>
3028 #include <asm/i8259.h>
3129 #include <asm/apic.h>
3230 #include <asm/timer.h>
3331 #include <asm/reboot.h>
3432 #include <asm/nmi.h>
33
+#include <clocksource/hyperv_timer.h>
3534
3635 struct ms_hyperv_info ms_hyperv;
3736 EXPORT_SYMBOL_GPL(ms_hyperv);
....@@ -42,11 +41,10 @@
4241 static void (*hv_kexec_handler)(void);
4342 static void (*hv_crash_handler)(struct pt_regs *regs);
4443
45
-__visible void __irq_entry hyperv_vector_handler(struct pt_regs *regs)
44
+DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback)
4645 {
4746 struct pt_regs *old_regs = set_irq_regs(regs);
4847
49
- entering_irq();
5048 inc_irq_stat(irq_hv_callback_count);
5149 if (vmbus_handler)
5250 vmbus_handler();
....@@ -54,13 +52,17 @@
5452 if (ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED)
5553 ack_APIC_irq();
5654
57
- exiting_irq();
5855 set_irq_regs(old_regs);
5956 }
6057
61
-void hv_setup_vmbus_irq(void (*handler)(void))
58
+int hv_setup_vmbus_irq(int irq, void (*handler)(void))
6259 {
60
+ /*
61
+ * The 'irq' argument is ignored on x86/x64 because a hard-coded
62
+ * interrupt vector is used for Hyper-V interrupts.
63
+ */
6364 vmbus_handler = handler;
65
+ return 0;
6466 }
6567
6668 void hv_remove_vmbus_irq(void)
....@@ -75,25 +77,23 @@
7577 * Routines to do per-architecture handling of stimer0
7678 * interrupts when in Direct Mode
7779 */
78
-
79
-__visible void __irq_entry hv_stimer0_vector_handler(struct pt_regs *regs)
80
+DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_stimer0)
8081 {
8182 struct pt_regs *old_regs = set_irq_regs(regs);
8283
83
- entering_irq();
8484 inc_irq_stat(hyperv_stimer0_count);
8585 if (hv_stimer0_handler)
8686 hv_stimer0_handler();
87
+ add_interrupt_randomness(HYPERV_STIMER0_VECTOR);
8788 ack_APIC_irq();
8889
89
- exiting_irq();
9090 set_irq_regs(old_regs);
9191 }
9292
9393 int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void))
9494 {
9595 *vector = HYPERV_STIMER0_VECTOR;
96
- *irq = 0; /* Unused on x86/x64 */
96
+ *irq = -1; /* Unused on x86/x64 */
9797 hv_stimer0_handler = handler;
9898 return 0;
9999 }
....@@ -135,14 +135,32 @@
135135 {
136136 if (kexec_in_progress && hv_kexec_handler)
137137 hv_kexec_handler();
138
+
139
+ /*
140
+ * Call hv_cpu_die() on all the CPUs, otherwise later the hypervisor
141
+ * corrupts the old VP Assist Pages and can crash the kexec kernel.
142
+ */
143
+ if (kexec_in_progress && hyperv_init_cpuhp > 0)
144
+ cpuhp_remove_state(hyperv_init_cpuhp);
145
+
146
+ /* The function calls stop_other_cpus(). */
138147 native_machine_shutdown();
148
+
149
+ /* Disable the hypercall page when there is only 1 active CPU. */
150
+ if (kexec_in_progress)
151
+ hyperv_cleanup();
139152 }
140153
141154 static void hv_machine_crash_shutdown(struct pt_regs *regs)
142155 {
143156 if (hv_crash_handler)
144157 hv_crash_handler(regs);
158
+
159
+ /* The function calls crash_smp_send_stop(). */
145160 native_machine_crash_shutdown(regs);
161
+
162
+ /* Disable the hypercall page when there is only 1 active CPU. */
163
+ hyperv_cleanup();
146164 }
147165 #endif /* CONFIG_KEXEC_CORE */
148166 #endif /* CONFIG_HYPERV */
....@@ -200,12 +218,26 @@
200218 return freq / 1000;
201219 }
202220
221
+#if defined(CONFIG_SMP) && IS_ENABLED(CONFIG_HYPERV)
222
+static void __init hv_smp_prepare_boot_cpu(void)
223
+{
224
+ native_smp_prepare_boot_cpu();
225
+#if defined(CONFIG_X86_64) && defined(CONFIG_PARAVIRT_SPINLOCKS)
226
+ hv_init_spinlocks();
227
+#endif
228
+}
229
+#endif
230
+
203231 static void __init ms_hyperv_init_platform(void)
204232 {
205233 int hv_host_info_eax;
206234 int hv_host_info_ebx;
207235 int hv_host_info_ecx;
208236 int hv_host_info_edx;
237
+
238
+#ifdef CONFIG_PARAVIRT
239
+ pv_info.name = "Hyper-V";
240
+#endif
209241
210242 /*
211243 * Extract the features and hints
....@@ -239,7 +271,7 @@
239271 hv_host_info_edx >> 24, hv_host_info_edx & 0xFFFFFF);
240272 }
241273
242
- if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
274
+ if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
243275 ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
244276 x86_platform.calibrate_tsc = hv_get_tsc_khz;
245277 x86_platform.calibrate_cpu = hv_get_tsc_khz;
....@@ -261,7 +293,7 @@
261293 crash_kexec_post_notifiers = true;
262294
263295 #ifdef CONFIG_X86_LOCAL_APIC
264
- if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
296
+ if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
265297 ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
266298 /*
267299 * Get the APIC frequency.
....@@ -270,9 +302,9 @@
270302
271303 rdmsrl(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency);
272304 hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ);
273
- lapic_timer_frequency = hv_lapic_frequency;
305
+ lapic_timer_period = hv_lapic_frequency;
274306 pr_info("Hyper-V: LAPIC Timer Frequency: %#x\n",
275
- lapic_timer_frequency);
307
+ lapic_timer_period);
276308 }
277309
278310 register_nmi_handler(NMI_UNKNOWN, hv_nmi_unknown, NMI_FLAG_FIRST,
....@@ -287,7 +319,10 @@
287319 machine_ops.shutdown = hv_machine_shutdown;
288320 machine_ops.crash_shutdown = hv_machine_crash_shutdown;
289321 #endif
290
- mark_tsc_unstable("running on Hyper-V");
322
+ if (ms_hyperv.features & HV_ACCESS_TSC_INVARIANT) {
323
+ wrmsrl(HV_X64_MSR_TSC_INVARIANT_CONTROL, 0x1);
324
+ setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
325
+ }
291326
292327 /*
293328 * Generation 2 instances don't support reading the NMI status from
....@@ -313,18 +348,45 @@
313348 x86_platform.apic_post_init = hyperv_init;
314349 hyperv_setup_mmu_ops();
315350 /* Setup the IDT for hypervisor callback */
316
- alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
351
+ alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_hyperv_callback);
317352
318353 /* Setup the IDT for reenlightenment notifications */
319
- if (ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT)
354
+ if (ms_hyperv.features & HV_ACCESS_REENLIGHTENMENT) {
320355 alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
321
- hyperv_reenlightenment_vector);
356
+ asm_sysvec_hyperv_reenlightenment);
357
+ }
322358
323359 /* Setup the IDT for stimer0 */
324
- if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE)
360
+ if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE) {
325361 alloc_intr_gate(HYPERV_STIMER0_VECTOR,
326
- hv_stimer0_callback_vector);
362
+ asm_sysvec_hyperv_stimer0);
363
+ }
364
+
365
+# ifdef CONFIG_SMP
366
+ smp_ops.smp_prepare_boot_cpu = hv_smp_prepare_boot_cpu;
367
+# endif
368
+
369
+ /*
370
+ * Hyper-V doesn't provide irq remapping for IO-APIC. To enable x2apic,
371
+ * set x2apic destination mode to physcial mode when x2apic is available
372
+ * and Hyper-V IOMMU driver makes sure cpus assigned with IO-APIC irqs
373
+ * have 8-bit APIC id.
374
+ */
375
+# ifdef CONFIG_X86_X2APIC
376
+ if (x2apic_supported())
377
+ x2apic_phys = 1;
378
+# endif
379
+
380
+ /* Register Hyper-V specific clocksource */
381
+ hv_init_clocksource();
327382 #endif
383
+ /*
384
+ * TSC should be marked as unstable only after Hyper-V
385
+ * clocksource has been initialized. This ensures that the
386
+ * stability of the sched_clock is not altered.
387
+ */
388
+ if (!(ms_hyperv.features & HV_ACCESS_TSC_INVARIANT))
389
+ mark_tsc_unstable("running on Hyper-V");
328390 }
329391
330392 const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {