Merge branch 'x86-hyperv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 hyperv updates from Ingo Molnar: "Misc updates to the hyperv guest code: - Rework clockevents initialization to better support hibernation - Allow guests to enable InvariantTSC - Micro-optimize send_ipi_one" * 'x86-hyperv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/hyperv: Initialize clockevents earlier in CPU onlining x86/hyperv: Allow guests to enable InvariantTSC x86/hyperv: Micro-optimize send_ipi_one()
This commit is contained in:
commit
64d6a12094
|
@ -194,10 +194,20 @@ do_ex_hypercall:
|
||||||
|
|
||||||
static bool __send_ipi_one(int cpu, int vector)
|
static bool __send_ipi_one(int cpu, int vector)
|
||||||
{
|
{
|
||||||
struct cpumask mask = CPU_MASK_NONE;
|
int vp = hv_cpu_number_to_vp_number(cpu);
|
||||||
|
|
||||||
cpumask_set_cpu(cpu, &mask);
|
trace_hyperv_send_ipi_one(cpu, vector);
|
||||||
return __send_ipi_mask(&mask, vector);
|
|
||||||
|
if (!hv_hypercall_pg || (vp == VP_INVAL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (vp >= 64)
|
||||||
|
return __send_ipi_mask_ex(cpumask_of(cpu), vector);
|
||||||
|
|
||||||
|
return !hv_do_fast_hypercall16(HVCALL_SEND_IPI, vector, BIT_ULL(vp));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hv_send_ipi(int cpu, int vector)
|
static void hv_send_ipi(int cpu, int vector)
|
||||||
|
|
|
@ -311,6 +311,12 @@ void __init hyperv_init(void)
|
||||||
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
|
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
|
||||||
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore any errors in setting up stimer clockevents
|
||||||
|
* as we can run with the LAPIC timer as a fallback.
|
||||||
|
*/
|
||||||
|
(void)hv_stimer_alloc();
|
||||||
|
|
||||||
hv_apic_init();
|
hv_apic_init();
|
||||||
|
|
||||||
x86_init.pci.arch_init = hv_pci_init;
|
x86_init.pci.arch_init = hv_pci_init;
|
||||||
|
|
|
@ -86,6 +86,8 @@
|
||||||
#define HV_X64_ACCESS_FREQUENCY_MSRS BIT(11)
|
#define HV_X64_ACCESS_FREQUENCY_MSRS BIT(11)
|
||||||
/* AccessReenlightenmentControls privilege */
|
/* AccessReenlightenmentControls privilege */
|
||||||
#define HV_X64_ACCESS_REENLIGHTENMENT BIT(13)
|
#define HV_X64_ACCESS_REENLIGHTENMENT BIT(13)
|
||||||
|
/* AccessTscInvariantControls privilege */
|
||||||
|
#define HV_X64_ACCESS_TSC_INVARIANT BIT(15)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Feature identification: indicates which flags were specified at partition
|
* Feature identification: indicates which flags were specified at partition
|
||||||
|
@ -278,6 +280,9 @@
|
||||||
#define HV_X64_MSR_TSC_EMULATION_CONTROL 0x40000107
|
#define HV_X64_MSR_TSC_EMULATION_CONTROL 0x40000107
|
||||||
#define HV_X64_MSR_TSC_EMULATION_STATUS 0x40000108
|
#define HV_X64_MSR_TSC_EMULATION_STATUS 0x40000108
|
||||||
|
|
||||||
|
/* TSC invariant control */
|
||||||
|
#define HV_X64_MSR_TSC_INVARIANT_CONTROL 0x40000118
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Declare the MSR used to setup pages used to communicate with the hypervisor.
|
* Declare the MSR used to setup pages used to communicate with the hypervisor.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -71,6 +71,21 @@ TRACE_EVENT(hyperv_send_ipi_mask,
|
||||||
__entry->ncpus, __entry->vector)
|
__entry->ncpus, __entry->vector)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(hyperv_send_ipi_one,
|
||||||
|
TP_PROTO(int cpu,
|
||||||
|
int vector),
|
||||||
|
TP_ARGS(cpu, vector),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(int, cpu)
|
||||||
|
__field(int, vector)
|
||||||
|
),
|
||||||
|
TP_fast_assign(__entry->cpu = cpu;
|
||||||
|
__entry->vector = vector;
|
||||||
|
),
|
||||||
|
TP_printk("cpu %d vector %x",
|
||||||
|
__entry->cpu, __entry->vector)
|
||||||
|
);
|
||||||
|
|
||||||
#endif /* CONFIG_HYPERV */
|
#endif /* CONFIG_HYPERV */
|
||||||
|
|
||||||
#undef TRACE_INCLUDE_PATH
|
#undef TRACE_INCLUDE_PATH
|
||||||
|
|
|
@ -290,7 +290,12 @@ static void __init ms_hyperv_init_platform(void)
|
||||||
machine_ops.shutdown = hv_machine_shutdown;
|
machine_ops.shutdown = hv_machine_shutdown;
|
||||||
machine_ops.crash_shutdown = hv_machine_crash_shutdown;
|
machine_ops.crash_shutdown = hv_machine_crash_shutdown;
|
||||||
#endif
|
#endif
|
||||||
mark_tsc_unstable("running on Hyper-V");
|
if (ms_hyperv.features & HV_X64_ACCESS_TSC_INVARIANT) {
|
||||||
|
wrmsrl(HV_X64_MSR_TSC_INVARIANT_CONTROL, 0x1);
|
||||||
|
setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
|
||||||
|
} else {
|
||||||
|
mark_tsc_unstable("running on Hyper-V");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generation 2 instances don't support reading the NMI status from
|
* Generation 2 instances don't support reading the NMI status from
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/clocksource.h>
|
#include <linux/clocksource.h>
|
||||||
#include <linux/sched_clock.h>
|
#include <linux/sched_clock.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/cpuhotplug.h>
|
||||||
#include <clocksource/hyperv_timer.h>
|
#include <clocksource/hyperv_timer.h>
|
||||||
#include <asm/hyperv-tlfs.h>
|
#include <asm/hyperv-tlfs.h>
|
||||||
#include <asm/mshyperv.h>
|
#include <asm/mshyperv.h>
|
||||||
|
@ -30,6 +31,15 @@ static u64 hv_sched_clock_offset __ro_after_init;
|
||||||
* mechanism is used when running on older versions of Hyper-V
|
* mechanism is used when running on older versions of Hyper-V
|
||||||
* that don't support Direct Mode. While Hyper-V provides
|
* that don't support Direct Mode. While Hyper-V provides
|
||||||
* four stimer's per CPU, Linux uses only stimer0.
|
* four stimer's per CPU, Linux uses only stimer0.
|
||||||
|
*
|
||||||
|
* Because Direct Mode does not require processing a VMbus
|
||||||
|
* message, stimer interrupts can be enabled earlier in the
|
||||||
|
* process of booting a CPU, and consistent with when timer
|
||||||
|
* interrupts are enabled for other clocksource drivers.
|
||||||
|
* However, for legacy versions of Hyper-V when Direct Mode
|
||||||
|
* is not enabled, setting up stimer interrupts must be
|
||||||
|
* delayed until VMbus is initialized and can process the
|
||||||
|
* interrupt message.
|
||||||
*/
|
*/
|
||||||
static bool direct_mode_enabled;
|
static bool direct_mode_enabled;
|
||||||
|
|
||||||
|
@ -102,17 +112,12 @@ static int hv_ce_set_oneshot(struct clock_event_device *evt)
|
||||||
/*
|
/*
|
||||||
* hv_stimer_init - Per-cpu initialization of the clockevent
|
* hv_stimer_init - Per-cpu initialization of the clockevent
|
||||||
*/
|
*/
|
||||||
void hv_stimer_init(unsigned int cpu)
|
static int hv_stimer_init(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ce;
|
struct clock_event_device *ce;
|
||||||
|
|
||||||
/*
|
if (!hv_clock_event)
|
||||||
* Synthetic timers are always available except on old versions of
|
return 0;
|
||||||
* Hyper-V on x86. In that case, just return as Linux will use a
|
|
||||||
* clocksource based on emulated PIT or LAPIC timer hardware.
|
|
||||||
*/
|
|
||||||
if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ce = per_cpu_ptr(hv_clock_event, cpu);
|
ce = per_cpu_ptr(hv_clock_event, cpu);
|
||||||
ce->name = "Hyper-V clockevent";
|
ce->name = "Hyper-V clockevent";
|
||||||
|
@ -127,28 +132,55 @@ void hv_stimer_init(unsigned int cpu)
|
||||||
HV_CLOCK_HZ,
|
HV_CLOCK_HZ,
|
||||||
HV_MIN_DELTA_TICKS,
|
HV_MIN_DELTA_TICKS,
|
||||||
HV_MAX_MAX_DELTA_TICKS);
|
HV_MAX_MAX_DELTA_TICKS);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hv_stimer_init);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hv_stimer_cleanup - Per-cpu cleanup of the clockevent
|
* hv_stimer_cleanup - Per-cpu cleanup of the clockevent
|
||||||
*/
|
*/
|
||||||
void hv_stimer_cleanup(unsigned int cpu)
|
int hv_stimer_cleanup(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct clock_event_device *ce;
|
struct clock_event_device *ce;
|
||||||
|
|
||||||
/* Turn off clockevent device */
|
if (!hv_clock_event)
|
||||||
if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) {
|
return 0;
|
||||||
ce = per_cpu_ptr(hv_clock_event, cpu);
|
|
||||||
|
/*
|
||||||
|
* In the legacy case where Direct Mode is not enabled
|
||||||
|
* (which can only be on x86/64), stimer cleanup happens
|
||||||
|
* relatively early in the CPU offlining process. We
|
||||||
|
* must unbind the stimer-based clockevent device so
|
||||||
|
* that the LAPIC timer can take over until clockevents
|
||||||
|
* are no longer needed in the offlining process. Note
|
||||||
|
* that clockevents_unbind_device() eventually calls
|
||||||
|
* hv_ce_shutdown().
|
||||||
|
*
|
||||||
|
* The unbind should not be done when Direct Mode is
|
||||||
|
* enabled because we may be on an architecture where
|
||||||
|
* there are no other clockevent devices to fallback to.
|
||||||
|
*/
|
||||||
|
ce = per_cpu_ptr(hv_clock_event, cpu);
|
||||||
|
if (direct_mode_enabled)
|
||||||
hv_ce_shutdown(ce);
|
hv_ce_shutdown(ce);
|
||||||
}
|
else
|
||||||
|
clockevents_unbind_device(ce, cpu);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hv_stimer_cleanup);
|
EXPORT_SYMBOL_GPL(hv_stimer_cleanup);
|
||||||
|
|
||||||
/* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */
|
/* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */
|
||||||
int hv_stimer_alloc(int sint)
|
int hv_stimer_alloc(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synthetic timers are always available except on old versions of
|
||||||
|
* Hyper-V on x86. In that case, return as error as Linux will use a
|
||||||
|
* clockevent based on emulated LAPIC timer hardware.
|
||||||
|
*/
|
||||||
|
if (!(ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
hv_clock_event = alloc_percpu(struct clock_event_device);
|
hv_clock_event = alloc_percpu(struct clock_event_device);
|
||||||
if (!hv_clock_event)
|
if (!hv_clock_event)
|
||||||
|
@ -159,22 +191,78 @@ int hv_stimer_alloc(int sint)
|
||||||
if (direct_mode_enabled) {
|
if (direct_mode_enabled) {
|
||||||
ret = hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector,
|
ret = hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector,
|
||||||
hv_stimer0_isr);
|
hv_stimer0_isr);
|
||||||
if (ret) {
|
if (ret)
|
||||||
free_percpu(hv_clock_event);
|
goto free_percpu;
|
||||||
hv_clock_event = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stimer0_message_sint = sint;
|
/*
|
||||||
return 0;
|
* Since we are in Direct Mode, stimer initialization
|
||||||
|
* can be done now with a CPUHP value in the same range
|
||||||
|
* as other clockevent devices.
|
||||||
|
*/
|
||||||
|
ret = cpuhp_setup_state(CPUHP_AP_HYPERV_TIMER_STARTING,
|
||||||
|
"clockevents/hyperv/stimer:starting",
|
||||||
|
hv_stimer_init, hv_stimer_cleanup);
|
||||||
|
if (ret < 0)
|
||||||
|
goto free_stimer0_irq;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
free_stimer0_irq:
|
||||||
|
hv_remove_stimer0_irq(stimer0_irq);
|
||||||
|
stimer0_irq = 0;
|
||||||
|
free_percpu:
|
||||||
|
free_percpu(hv_clock_event);
|
||||||
|
hv_clock_event = NULL;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hv_stimer_alloc);
|
EXPORT_SYMBOL_GPL(hv_stimer_alloc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hv_stimer_legacy_init -- Called from the VMbus driver to handle
|
||||||
|
* the case when Direct Mode is not enabled, and the stimer
|
||||||
|
* must be initialized late in the CPU onlining process.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void hv_stimer_legacy_init(unsigned int cpu, int sint)
|
||||||
|
{
|
||||||
|
if (direct_mode_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function gets called by each vCPU, so setting the
|
||||||
|
* global stimer_message_sint value each time is conceptually
|
||||||
|
* not ideal, but the value passed in is always the same and
|
||||||
|
* it avoids introducing yet another interface into this
|
||||||
|
* clocksource driver just to set the sint in the legacy case.
|
||||||
|
*/
|
||||||
|
stimer0_message_sint = sint;
|
||||||
|
(void)hv_stimer_init(cpu);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(hv_stimer_legacy_init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hv_stimer_legacy_cleanup -- Called from the VMbus driver to
|
||||||
|
* handle the case when Direct Mode is not enabled, and the
|
||||||
|
* stimer must be cleaned up early in the CPU offlining
|
||||||
|
* process.
|
||||||
|
*/
|
||||||
|
void hv_stimer_legacy_cleanup(unsigned int cpu)
|
||||||
|
{
|
||||||
|
if (direct_mode_enabled)
|
||||||
|
return;
|
||||||
|
(void)hv_stimer_cleanup(cpu);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(hv_stimer_legacy_cleanup);
|
||||||
|
|
||||||
|
|
||||||
/* hv_stimer_free - Free global resources allocated by hv_stimer_alloc() */
|
/* hv_stimer_free - Free global resources allocated by hv_stimer_alloc() */
|
||||||
void hv_stimer_free(void)
|
void hv_stimer_free(void)
|
||||||
{
|
{
|
||||||
if (direct_mode_enabled && (stimer0_irq != 0)) {
|
if (!hv_clock_event)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (direct_mode_enabled) {
|
||||||
|
cpuhp_remove_state(CPUHP_AP_HYPERV_TIMER_STARTING);
|
||||||
hv_remove_stimer0_irq(stimer0_irq);
|
hv_remove_stimer0_irq(stimer0_irq);
|
||||||
stimer0_irq = 0;
|
stimer0_irq = 0;
|
||||||
}
|
}
|
||||||
|
@ -190,14 +278,20 @@ EXPORT_SYMBOL_GPL(hv_stimer_free);
|
||||||
void hv_stimer_global_cleanup(void)
|
void hv_stimer_global_cleanup(void)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
struct clock_event_device *ce;
|
|
||||||
|
|
||||||
if (ms_hyperv.features & HV_MSR_SYNTIMER_AVAILABLE) {
|
/*
|
||||||
for_each_present_cpu(cpu) {
|
* hv_stime_legacy_cleanup() will stop the stimer if Direct
|
||||||
ce = per_cpu_ptr(hv_clock_event, cpu);
|
* Mode is not enabled, and fallback to the LAPIC timer.
|
||||||
clockevents_unbind_device(ce, cpu);
|
*/
|
||||||
}
|
for_each_present_cpu(cpu) {
|
||||||
|
hv_stimer_legacy_cleanup(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If Direct Mode is enabled, the cpuhp teardown callback
|
||||||
|
* (hv_stimer_cleanup) will be run on all CPUs to stop the
|
||||||
|
* stimers.
|
||||||
|
*/
|
||||||
hv_stimer_free();
|
hv_stimer_free();
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup);
|
EXPORT_SYMBOL_GPL(hv_stimer_global_cleanup);
|
||||||
|
|
|
@ -202,7 +202,7 @@ int hv_synic_init(unsigned int cpu)
|
||||||
{
|
{
|
||||||
hv_synic_enable_regs(cpu);
|
hv_synic_enable_regs(cpu);
|
||||||
|
|
||||||
hv_stimer_init(cpu);
|
hv_stimer_legacy_init(cpu, VMBUS_MESSAGE_SINT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ int hv_synic_cleanup(unsigned int cpu)
|
||||||
if (channel_found && vmbus_connection.conn_state == CONNECTED)
|
if (channel_found && vmbus_connection.conn_state == CONNECTED)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
hv_stimer_cleanup(cpu);
|
hv_stimer_legacy_cleanup(cpu);
|
||||||
|
|
||||||
hv_synic_disable_regs(cpu);
|
hv_synic_disable_regs(cpu);
|
||||||
|
|
||||||
|
|
|
@ -1340,10 +1340,6 @@ static int vmbus_bus_init(void)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_alloc;
|
goto err_alloc;
|
||||||
|
|
||||||
ret = hv_stimer_alloc(VMBUS_MESSAGE_SINT);
|
|
||||||
if (ret < 0)
|
|
||||||
goto err_alloc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the per-cpu interrupt state and stimer state.
|
* Initialize the per-cpu interrupt state and stimer state.
|
||||||
* Then connect to the host.
|
* Then connect to the host.
|
||||||
|
@ -1400,9 +1396,8 @@ static int vmbus_bus_init(void)
|
||||||
err_connect:
|
err_connect:
|
||||||
cpuhp_remove_state(hyperv_cpuhp_online);
|
cpuhp_remove_state(hyperv_cpuhp_online);
|
||||||
err_cpuhp:
|
err_cpuhp:
|
||||||
hv_stimer_free();
|
|
||||||
err_alloc:
|
|
||||||
hv_synic_free();
|
hv_synic_free();
|
||||||
|
err_alloc:
|
||||||
hv_remove_vmbus_irq();
|
hv_remove_vmbus_irq();
|
||||||
|
|
||||||
bus_unregister(&hv_bus);
|
bus_unregister(&hv_bus);
|
||||||
|
@ -2315,20 +2310,23 @@ static void hv_crash_handler(struct pt_regs *regs)
|
||||||
static int hv_synic_suspend(void)
|
static int hv_synic_suspend(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* When we reach here, all the non-boot CPUs have been offlined, and
|
* When we reach here, all the non-boot CPUs have been offlined.
|
||||||
* the stimers on them have been unbound in hv_synic_cleanup() ->
|
* If we're in a legacy configuration where stimer Direct Mode is
|
||||||
|
* not enabled, the stimers on the non-boot CPUs have been unbound
|
||||||
|
* in hv_synic_cleanup() -> hv_stimer_legacy_cleanup() ->
|
||||||
* hv_stimer_cleanup() -> clockevents_unbind_device().
|
* hv_stimer_cleanup() -> clockevents_unbind_device().
|
||||||
*
|
*
|
||||||
* hv_synic_suspend() only runs on CPU0 with interrupts disabled. Here
|
* hv_synic_suspend() only runs on CPU0 with interrupts disabled.
|
||||||
* we do not unbind the stimer on CPU0 because: 1) it's unnecessary
|
* Here we do not call hv_stimer_legacy_cleanup() on CPU0 because:
|
||||||
* because the interrupts remain disabled between syscore_suspend()
|
* 1) it's unnecessary as interrupts remain disabled between
|
||||||
* and syscore_resume(): see create_image() and resume_target_kernel();
|
* syscore_suspend() and syscore_resume(): see create_image() and
|
||||||
|
* resume_target_kernel()
|
||||||
* 2) the stimer on CPU0 is automatically disabled later by
|
* 2) the stimer on CPU0 is automatically disabled later by
|
||||||
* syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ...
|
* syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ...
|
||||||
* -> clockevents_shutdown() -> ... -> hv_ce_shutdown(); 3) a warning
|
* -> clockevents_shutdown() -> ... -> hv_ce_shutdown()
|
||||||
* would be triggered if we call clockevents_unbind_device(), which
|
* 3) a warning would be triggered if we call
|
||||||
* may sleep, in an interrupts-disabled context. So, we intentionally
|
* clockevents_unbind_device(), which may sleep, in an
|
||||||
* don't call hv_stimer_cleanup(0) here.
|
* interrupts-disabled context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hv_synic_disable_regs(0);
|
hv_synic_disable_regs(0);
|
||||||
|
|
|
@ -21,10 +21,11 @@
|
||||||
#define HV_MIN_DELTA_TICKS 1
|
#define HV_MIN_DELTA_TICKS 1
|
||||||
|
|
||||||
/* Routines called by the VMbus driver */
|
/* Routines called by the VMbus driver */
|
||||||
extern int hv_stimer_alloc(int sint);
|
extern int hv_stimer_alloc(void);
|
||||||
extern void hv_stimer_free(void);
|
extern void hv_stimer_free(void);
|
||||||
extern void hv_stimer_init(unsigned int cpu);
|
extern int hv_stimer_cleanup(unsigned int cpu);
|
||||||
extern void hv_stimer_cleanup(unsigned int cpu);
|
extern void hv_stimer_legacy_init(unsigned int cpu, int sint);
|
||||||
|
extern void hv_stimer_legacy_cleanup(unsigned int cpu);
|
||||||
extern void hv_stimer_global_cleanup(void);
|
extern void hv_stimer_global_cleanup(void);
|
||||||
extern void hv_stimer0_isr(void);
|
extern void hv_stimer0_isr(void);
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,7 @@ enum cpuhp_state {
|
||||||
CPUHP_AP_ARC_TIMER_STARTING,
|
CPUHP_AP_ARC_TIMER_STARTING,
|
||||||
CPUHP_AP_RISCV_TIMER_STARTING,
|
CPUHP_AP_RISCV_TIMER_STARTING,
|
||||||
CPUHP_AP_CSKY_TIMER_STARTING,
|
CPUHP_AP_CSKY_TIMER_STARTING,
|
||||||
|
CPUHP_AP_HYPERV_TIMER_STARTING,
|
||||||
CPUHP_AP_KVM_STARTING,
|
CPUHP_AP_KVM_STARTING,
|
||||||
CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
|
CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
|
||||||
CPUHP_AP_KVM_ARM_VGIC_STARTING,
|
CPUHP_AP_KVM_ARM_VGIC_STARTING,
|
||||||
|
|
Loading…
Reference in New Issue