linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: arjan@linux.intel.com
To: linux-pm@vger.kernel.org
Cc: artem.bityutskiy@linux.intel.com, rafael@kernel.org,
	Arjan van de Ven <arjan.van.de.ven@intel.com>,
	Arjan van de Ven <arjan@linux.intel.com>
Subject: [PATCH 6/7] intel_idle: Add support for using intel_idle in a VM guest using just hlt
Date: Thu,  1 Jun 2023 18:28:00 +0000	[thread overview]
Message-ID: <20230601182801.2622044-7-arjan@linux.intel.com> (raw)
In-Reply-To: <20230601182801.2622044-1-arjan@linux.intel.com>

From: Arjan van de Ven <arjan.van.de.ven@intel.com>

In a typical VM guest, the mwait instruction is not available, leaving only the
'hlt' instruction (which causes a VMEXIT to the host).

So currently, intel_idle will detect the lack of mwait, and fail
to initialize (after which another idle method would step in which will
just use hlt always).

By providing capability to do this with the intel_idle driver, we can
do better than this fallback. While this current change only gets us parity
to the existing behavior, later patches in this series will add new capabilities.

In order to do this, a simplified version of the initialization function
for VM guests is created, and this will be called if the CPU is recognized,
but mwait is not supported, and we're in a VM guest.

One thing to note is that the latency (and break even) of this C1 state
is higher than the typical bare metal C1 state. Because hlt causes a vmexit,
and the cost of vmexit + hypervisor overhead + vmenter is typically in the
order of upto 5 microseconds... even if the hypervisor does not actually
goes into a hardware power saving state.

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
 drivers/idle/intel_idle.c | 54 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 55c3e6ece3dd..c4929d8a35a4 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -1280,6 +1280,18 @@ static struct cpuidle_state snr_cstates[] __initdata = {
 		.enter = NULL }
 };
 
+static struct cpuidle_state vmguest_cstates[] __initdata = {
+	{
+		.name = "C1",
+		.desc = "HLT",
+		.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_IRQ_ENABLE,
+		.exit_latency = 5,
+		.target_residency = 10,
+		.enter = &intel_idle_hlt_irq, },
+	{
+		.enter = NULL }
+};
+
 static const struct idle_cpu idle_cpu_nehalem __initconst = {
 	.state_table = nehalem_cstates,
 	.auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
@@ -2105,6 +2117,46 @@ static void __init intel_idle_cpuidle_devices_uninit(void)
 		cpuidle_unregister_device(per_cpu_ptr(intel_idle_cpuidle_devices, i));
 }
 
+static int __init intel_idle_vminit(const struct x86_cpu_id *id)
+{
+	int retval;
+
+	cpuidle_state_table = vmguest_cstates;
+	skip_mwait_check = true; /* hypervisor hides mwait from us normally */
+
+	icpu = (const struct idle_cpu *)id->driver_data;
+
+	pr_debug("v" INTEL_IDLE_VERSION " model 0x%X\n",
+		 boot_cpu_data.x86_model);
+
+	intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+	if (!intel_idle_cpuidle_devices)
+		return -ENOMEM;
+
+	intel_idle_cpuidle_driver_init(&intel_idle_driver);
+
+	retval = cpuidle_register_driver(&intel_idle_driver);
+	if (retval) {
+		struct cpuidle_driver *drv = cpuidle_get_driver();
+		printk(KERN_DEBUG pr_fmt("intel_idle yielding to %s\n"),
+		       drv ? drv->name : "none");
+		goto init_driver_fail;
+	}
+
+	retval = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "idle/intel:online",
+				   intel_idle_cpu_online, NULL);
+	if (retval < 0)
+		goto hp_setup_fail;
+
+	return 0;
+hp_setup_fail:
+	intel_idle_cpuidle_devices_uninit();
+	cpuidle_unregister_driver(&intel_idle_driver);
+init_driver_fail:
+	free_percpu(intel_idle_cpuidle_devices);
+	return retval;
+}
+
 static int __init intel_idle_init(void)
 {
 	const struct x86_cpu_id *id;
@@ -2123,6 +2175,8 @@ static int __init intel_idle_init(void)
 	id = x86_match_cpu(intel_idle_ids);
 	if (id) {
 		if (!boot_cpu_has(X86_FEATURE_MWAIT)) {
+			if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+				return intel_idle_vminit(id);
 			pr_debug("Please enable MWAIT in BIOS SETUP\n");
 			return -ENODEV;
 		}
-- 
2.40.1


  parent reply	other threads:[~2023-06-01 18:31 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-01 18:27 [PATCH 00/7 Add support for running in VM guests to intel_idle arjan
2023-06-01 18:27 ` [PATCH 1/7] intel_idle: refactor state->enter manipulation into its own function arjan
2023-06-01 18:27 ` [PATCH 2/7] intel_idle: clean up the (new) state_update_enter_method function arjan
2023-06-04 15:34   ` Rafael J. Wysocki
2023-06-04 22:35     ` Van De Ven, Arjan
2023-06-01 18:27 ` [PATCH 3/7] intel_idle: Add a sanity check in the new " arjan
2023-06-04 15:43   ` Rafael J. Wysocki
2023-06-01 18:27 ` [PATCH 4/7] intel_idle: Add helper functions to support 'hlt' as idle state arjan
2023-06-04 15:46   ` Rafael J. Wysocki
2023-06-01 18:27 ` [PATCH 5/7] intel_idle: Add a way to skip the mwait check on all states arjan
2023-06-04 15:54   ` Rafael J. Wysocki
2023-06-05 15:24     ` Arjan van de Ven
2023-06-01 18:28 ` arjan [this message]
2023-06-04 15:59   ` [PATCH 6/7] intel_idle: Add support for using intel_idle in a VM guest using just hlt Rafael J. Wysocki
2023-06-04 22:34     ` Van De Ven, Arjan
2023-06-01 18:28 ` [PATCH 7/7] intel_idle: Add a "Long HLT" C1 state for the VM guest mode arjan
2023-06-04 15:01 ` [PATCH 00/7 Add support for running in VM guests to intel_idle Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230601182801.2622044-7-arjan@linux.intel.com \
    --to=arjan@linux.intel.com \
    --cc=arjan.van.de.ven@intel.com \
    --cc=artem.bityutskiy@linux.intel.com \
    --cc=linux-pm@vger.kernel.org \
    --cc=rafael@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).