Commit a1c4423b authored by Marcelo Tosatti's avatar Marcelo Tosatti Committed by Rafael J. Wysocki
Browse files

cpuidle-haltpoll: disable host side polling when kvm virtualized



When performing guest side polling, it is not necessary to
also perform host side polling.

So disable host side polling, via the new MSR interface,
when loading cpuidle-haltpoll driver.

Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 2cffe9f6
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -794,6 +794,7 @@ config KVM_GUEST
	bool "KVM Guest support (including kvmclock)"
	depends on PARAVIRT
	select PARAVIRT_CLOCK
	select ARCH_CPUIDLE_HALTPOLL
	default y
	---help---
	  This option enables various optimizations for running under the KVM
@@ -802,6 +803,12 @@ config KVM_GUEST
	  underlying device model, the host provides the guest with
	  timing infrastructure such as time of day, and system time

config ARCH_CPUIDLE_HALTPOLL
        def_bool n
        prompt "Disable host haltpoll when loading haltpoll driver"
        help
	  If virtualized under KVM, disable host haltpoll.

config PVH
	bool "Support for running PVH guests"
	---help---
+8 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ARCH_HALTPOLL_H
#define _ARCH_HALTPOLL_H

void arch_haltpoll_enable(void);
void arch_haltpoll_disable(void);

#endif
+42 −0
Original line number Diff line number Diff line
@@ -875,3 +875,45 @@ void __init kvm_spinlock_init(void)
}

#endif	/* CONFIG_PARAVIRT_SPINLOCKS */

#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL

static void kvm_disable_host_haltpoll(void *i)
{
	wrmsrl(MSR_KVM_POLL_CONTROL, 0);
}

static void kvm_enable_host_haltpoll(void *i)
{
	wrmsrl(MSR_KVM_POLL_CONTROL, 1);
}

void arch_haltpoll_enable(void)
{
	if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) {
		printk(KERN_ERR "kvm: host does not support poll control\n");
		printk(KERN_ERR "kvm: host upgrade recommended\n");
		return;
	}

	preempt_disable();
	/* Enable guest halt poll disables host halt poll */
	kvm_disable_host_haltpoll(NULL);
	smp_call_function(kvm_disable_host_haltpoll, NULL, 1);
	preempt_enable();
}
EXPORT_SYMBOL_GPL(arch_haltpoll_enable);

void arch_haltpoll_disable(void)
{
	if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL))
		return;

	preempt_disable();
	/* Enable guest halt poll disables host halt poll */
	kvm_enable_host_haltpoll(NULL);
	smp_call_function(kvm_enable_host_haltpoll, NULL, 1);
	preempt_enable();
}
EXPORT_SYMBOL_GPL(arch_haltpoll_disable);
#endif
+8 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/sched/idle.h>
#include <linux/kvm_para.h>
#include <linux/cpuidle_haltpoll.h>

static int default_enter_idle(struct cpuidle_device *dev,
			      struct cpuidle_driver *drv, int index)
@@ -47,6 +48,7 @@ static struct cpuidle_driver haltpoll_driver = {

static int __init haltpoll_init(void)
{
	int ret;
	struct cpuidle_driver *drv = &haltpoll_driver;

	cpuidle_poll_state_init(drv);
@@ -54,11 +56,16 @@ static int __init haltpoll_init(void)
	if (!kvm_para_available())
		return 0;

	return cpuidle_register(&haltpoll_driver, NULL);
	ret = cpuidle_register(&haltpoll_driver, NULL);
	if (ret == 0)
		arch_haltpoll_enable();

	return ret;
}

static void __exit haltpoll_exit(void)
{
	arch_haltpoll_disable();
	cpuidle_unregister(&haltpoll_driver);
}

+16 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CPUIDLE_HALTPOLL_H
#define _CPUIDLE_HALTPOLL_H

#ifdef CONFIG_ARCH_CPUIDLE_HALTPOLL
#include <asm/cpuidle_haltpoll.h>
#else
static inline void arch_haltpoll_enable(void)
{
}

static inline void arch_haltpoll_disable(void)
{
}
#endif
#endif