intel_idle: Avoid using deep idle states during initialization

Commit c0f6913889 ("intel_idle: Use subsys_initcall_sync() for
initialization") effectively made intel_idle initialize earlier which
turns out to interfere with USB EHCI probing on some platforms [1].
Investigation led to the conclusion that this was related to allowing
package idle states to be used earlier than before.

Work around that issue by making intel_idle set a CPU latency QoS
request to prevent package idle states from being used on all platforms
supported by it for the duration of the device_initcall() initialization
phase.

Fixes: c0f6913889 ("intel_idle: Use subsys_initcall_sync() for initialization")
Reported-by: Julian Silver <mendaxca@gmail.com>
Tested-by: Julian Silver <mendaxca@gmail.com>
Closes: https://lore.kernel.org/linux-acpi/3353bdf3-4f33-44b1-809b-b0378bee5816@gmail.com/
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/5120454.31r3eYUQgx@rafael.j.wysocki
This commit is contained in:
Rafael J. Wysocki
2026-08-03 20:11:10 +02:00
parent 075b74841b
commit 9eadbed788

View File

@@ -53,6 +53,7 @@
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/moduleparam.h>
#include <linux/pm_qos.h>
#include <linux/sysfs.h>
#include <asm/cpuid/api.h>
#include <asm/cpu_device_id.h>
@@ -2697,6 +2698,9 @@ static void __init cmdline_table_adjust(struct cpuidle_driver *drv)
pr_info("Failed to adjust C-states with data from 'intel_idle.table'\n");
}
#define INTEL_IDLE_INIT_QOS 20
static struct pm_qos_request qos_req __initdata;
static int __init intel_idle_init(void)
{
const struct x86_cpu_id *id;
@@ -2766,6 +2770,13 @@ static int __init intel_idle_init(void)
if (retval)
pr_warn("failed to initialized sysfs");
/*
* Some platforms, in particular the Intel S1200BTL motherboard, have a
* problem with using package idle states too early, so prevent that
* from taking place until the device_initcall() phase is over.
*/
cpu_latency_qos_add_request(&qos_req, INTEL_IDLE_INIT_QOS);
retval = cpuidle_register_driver(&intel_idle_driver);
if (retval) {
struct cpuidle_driver *drv = cpuidle_get_driver();
@@ -2790,6 +2801,9 @@ static int __init intel_idle_init(void)
intel_idle_cpuidle_devices_uninit();
cpuidle_unregister_driver(&intel_idle_driver);
init_driver_fail:
if (cpu_latency_qos_request_active((&qos_req)))
cpu_latency_qos_remove_request(&qos_req);
intel_idle_sysfs_uninit();
free_percpu(intel_idle_cpuidle_devices);
return retval;
@@ -2797,6 +2811,15 @@ static int __init intel_idle_init(void)
}
subsys_initcall_sync(intel_idle_init);
static int __init intel_idle_init_complete(void)
{
if (cpu_latency_qos_request_active((&qos_req)))
cpu_latency_qos_remove_request(&qos_req);
return 0;
}
device_initcall_sync(intel_idle_init_complete);
/*
* We are not really modular, but we used to support that. Meaning we also
* support "intel_idle.max_cstate=..." at boot and also a read-only export of