2010-03-08 22:07:30 +03:00
/*
* intel_idle . c - native hardware idle loop for modern Intel processors
*
2013-11-09 09:30:17 +04:00
* Copyright ( c ) 2013 , Intel Corporation .
2010-03-08 22:07:30 +03:00
* Len Brown < len . brown @ intel . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
/*
* intel_idle is a cpuidle driver that loads on specific Intel processors
* in lieu of the legacy ACPI processor_idle driver . The intent is to
* make Linux more efficient on these processors , as intel_idle knows
* more than ACPI , as well as make Linux more immune to ACPI BIOS bugs .
*/
/*
* Design Assumptions
*
* All CPUs have same idle states as boot CPU
*
* Chipset BM_STS ( bus master status ) bit is a NOP
* for preventing entry into deep C - stats
*/
/*
* Known limitations
*
* The driver currently initializes for_each_online_cpu ( ) upon modprobe .
* It it unaware of subsequent processors hot - added to the system .
* This means that if you boot with maxcpus = n and later online
* processors above n , those processors will use C1 only .
*
* ACPI has a . suspend hack to turn off deep c - statees during suspend
* to avoid complications with the lapic timer workaround .
* Have not seen issues with suspend , but may need same workaround here .
*
*/
/* un-comment DEBUG to enable pr_debug() statements */
# define DEBUG
2017-06-09 22:29:20 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2010-03-08 22:07:30 +03:00
# include <linux/kernel.h>
# include <linux/cpuidle.h>
2015-04-03 03:02:34 +03:00
# include <linux/tick.h>
2010-03-08 22:07:30 +03:00
# include <trace/events/power.h>
# include <linux/sched.h>
2011-01-10 04:38:12 +03:00
# include <linux/notifier.h>
# include <linux/cpu.h>
2016-06-17 08:28:33 +03:00
# include <linux/moduleparam.h>
2012-01-26 03:09:07 +04:00
# include <asm/cpu_device_id.h>
2016-06-03 03:19:32 +03:00
# include <asm/intel-family.h>
2010-09-18 02:36:40 +04:00
# include <asm/mwait.h>
2011-01-19 04:48:27 +03:00
# include <asm/msr.h>
2010-03-08 22:07:30 +03:00
2016-03-13 08:33:48 +03:00
# define INTEL_IDLE_VERSION "0.4.1"
2010-03-08 22:07:30 +03:00
static struct cpuidle_driver intel_idle_driver = {
. name = " intel_idle " ,
. owner = THIS_MODULE ,
} ;
/* intel_idle.max_cstate=0 disables driver */
2013-02-02 06:35:35 +04:00
static int max_cstate = CPUIDLE_STATE_MAX - 1 ;
2010-03-08 22:07:30 +03:00
2010-05-28 10:22:03 +04:00
static unsigned int mwait_substates ;
2010-03-08 22:07:30 +03:00
2011-01-10 04:38:12 +03:00
# define LAPIC_TIMER_ALWAYS_RELIABLE 0xFFFFFFFF
2010-03-08 22:07:30 +03:00
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
2010-07-07 08:12:03 +04:00
static unsigned int lapic_timer_reliable_states = ( 1 < < 1 ) ; /* Default to only C1 */
2010-03-08 22:07:30 +03:00
2012-01-26 03:09:07 +04:00
struct idle_cpu {
struct cpuidle_state * state_table ;
/*
* Hardware C - state auto - demotion may not always be optimal .
* Indicate which enable bits to clear here .
*/
unsigned long auto_demotion_disable_flags ;
2014-07-31 23:21:24 +04:00
bool byt_auto_demotion_disable_flag ;
2013-02-02 10:31:56 +04:00
bool disable_promotion_to_c1e ;
2012-01-26 03:09:07 +04:00
} ;
static const struct idle_cpu * icpu ;
2010-08-07 22:10:03 +04:00
static struct cpuidle_device __percpu * intel_idle_cpuidle_devices ;
2011-10-28 14:50:42 +04:00
static int intel_idle ( struct cpuidle_device * dev ,
struct cpuidle_driver * drv , int index ) ;
2017-08-10 01:14:45 +03:00
static void intel_idle_s2idle ( struct cpuidle_device * dev ,
2015-02-11 07:04:17 +03:00
struct cpuidle_driver * drv , int index ) ;
2010-03-08 22:07:30 +03:00
static struct cpuidle_state * cpuidle_state_table ;
2011-01-12 10:51:20 +03:00
/*
* Set this flag for states where the HW flushes the TLB for us
* and so we don ' t need cross - calls to keep it consistent .
* If this flag is set , SW flushes the TLB , so even if the
* HW doesn ' t do the flushing , this flag is safe to use .
*/
# define CPUIDLE_FLAG_TLB_FLUSHED 0x10000
2013-02-01 04:55:37 +04:00
/*
* MWAIT takes an 8 - bit " hint " in EAX " suggesting "
* the C - state ( top nibble ) and sub - state ( bottom nibble )
* 0x00 means " MWAIT(C1) " , 0x10 means " MWAIT(C2) " etc .
*
* We store the hint at the top of our " flags " for each state .
*/
# define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
# define MWAIT2flg(eax) ((eax & 0xFF) << 24)
2010-03-08 22:07:30 +03:00
/*
* States are indexed by the cstate number ,
* which is also the index into the MWAIT hint array .
* Thus C0 is a dummy .
*/
2014-01-09 11:30:26 +04:00
static struct cpuidle_state nehalem_cstates [ ] = {
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2010-03-08 22:07:30 +03:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2010-03-08 22:07:30 +03:00
. exit_latency = 3 ,
. target_residency = 6 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 10:31:56 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2013-02-02 10:31:56 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2013-02-02 10:31:56 +04:00
. exit_latency = 10 ,
. target_residency = 20 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2010-03-08 22:07:30 +03:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-03-08 22:07:30 +03:00
. exit_latency = 20 ,
. target_residency = 80 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2010-03-08 22:07:30 +03:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-03-08 22:07:30 +03:00
. exit_latency = 200 ,
. target_residency = 800 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
. enter = NULL }
2010-03-08 22:07:30 +03:00
} ;
2014-01-09 11:30:26 +04:00
static struct cpuidle_state snb_cstates [ ] = {
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2010-07-07 08:12:03 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2013-02-02 10:31:56 +04:00
. exit_latency = 2 ,
. target_residency = 2 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 10:31:56 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2013-02-02 10:31:56 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2013-02-02 10:31:56 +04:00
. exit_latency = 10 ,
. target_residency = 20 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2010-07-07 08:12:03 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-07-07 08:12:03 +04:00
. exit_latency = 80 ,
2010-12-14 02:28:22 +03:00
. target_residency = 211 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2010-07-07 08:12:03 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-07-07 08:12:03 +04:00
. exit_latency = 104 ,
2010-12-14 02:28:22 +03:00
. target_residency = 345 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C7 " ,
2010-07-07 08:12:03 +04:00
. desc = " MWAIT 0x30 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x30 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-07-07 08:12:03 +04:00
. exit_latency = 109 ,
2010-12-14 02:28:22 +03:00
. target_residency = 345 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
. enter = NULL }
2010-07-07 08:12:03 +04:00
} ;
2014-02-14 11:30:00 +04:00
static struct cpuidle_state byt_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2014-02-14 11:30:00 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2014-02-14 11:30:00 +04:00
. exit_latency = 1 ,
. target_residency = 1 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-14 11:30:00 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6N " ,
2014-02-14 11:30:00 +04:00
. desc = " MWAIT 0x58 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x58 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2015-03-25 06:23:20 +03:00
. exit_latency = 300 ,
2014-02-14 11:30:00 +04:00
. target_residency = 275 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-14 11:30:00 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6S " ,
2014-02-14 11:30:00 +04:00
. desc = " MWAIT 0x52 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x52 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2015-03-25 06:23:20 +03:00
. exit_latency = 500 ,
2014-02-14 11:30:00 +04:00
. target_residency = 560 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-14 11:30:00 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C7 " ,
2014-02-14 11:30:00 +04:00
. desc = " MWAIT 0x60 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-14 11:30:00 +04:00
. exit_latency = 1200 ,
2015-03-25 06:23:20 +03:00
. target_residency = 4000 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-14 11:30:00 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C7S " ,
2014-02-14 11:30:00 +04:00
. desc = " MWAIT 0x64 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x64 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-14 11:30:00 +04:00
. exit_latency = 10000 ,
. target_residency = 20000 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-14 11:30:00 +04:00
{
. enter = NULL }
} ;
2015-03-28 03:54:01 +03:00
static struct cpuidle_state cht_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2015-03-28 03:54:01 +03:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 1 ,
. target_residency = 1 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-28 03:54:01 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6N " ,
2015-03-28 03:54:01 +03:00
. desc = " MWAIT 0x58 " ,
. flags = MWAIT2flg ( 0x58 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 80 ,
. target_residency = 275 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-28 03:54:01 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6S " ,
2015-03-28 03:54:01 +03:00
. desc = " MWAIT 0x52 " ,
. flags = MWAIT2flg ( 0x52 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 200 ,
. target_residency = 560 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-28 03:54:01 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C7 " ,
2015-03-28 03:54:01 +03:00
. desc = " MWAIT 0x60 " ,
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 1200 ,
. target_residency = 4000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-28 03:54:01 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C7S " ,
2015-03-28 03:54:01 +03:00
. desc = " MWAIT 0x64 " ,
. flags = MWAIT2flg ( 0x64 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 10000 ,
. target_residency = 20000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-28 03:54:01 +03:00
{
. enter = NULL }
} ;
2014-01-09 11:30:26 +04:00
static struct cpuidle_state ivb_cstates [ ] = {
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2012-06-02 03:45:32 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2012-06-02 03:45:32 +04:00
. exit_latency = 1 ,
. target_residency = 1 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 10:31:56 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2013-02-02 10:31:56 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2013-02-02 10:31:56 +04:00
. exit_latency = 10 ,
. target_residency = 20 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2012-06-02 03:45:32 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2012-06-02 03:45:32 +04:00
. exit_latency = 59 ,
. target_residency = 156 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2012-06-02 03:45:32 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2012-06-02 03:45:32 +04:00
. exit_latency = 80 ,
. target_residency = 300 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C7 " ,
2012-06-02 03:45:32 +04:00
. desc = " MWAIT 0x30 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x30 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2012-06-02 03:45:32 +04:00
. exit_latency = 87 ,
. target_residency = 300 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
. enter = NULL }
2012-06-02 03:45:32 +04:00
} ;
2014-04-04 09:21:07 +04:00
static struct cpuidle_state ivt_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2014-04-04 09:21:07 +04:00
. exit_latency = 1 ,
. target_residency = 1 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2014-04-04 09:21:07 +04:00
. exit_latency = 10 ,
. target_residency = 80 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-04-04 09:21:07 +04:00
. exit_latency = 59 ,
. target_residency = 156 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-04-04 09:21:07 +04:00
. exit_latency = 82 ,
. target_residency = 300 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
. enter = NULL }
} ;
static struct cpuidle_state ivt_cstates_4s [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2014-04-04 09:21:07 +04:00
. exit_latency = 1 ,
. target_residency = 1 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2014-04-04 09:21:07 +04:00
. exit_latency = 10 ,
. target_residency = 250 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-04-04 09:21:07 +04:00
. exit_latency = 59 ,
. target_residency = 300 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-04-04 09:21:07 +04:00
. exit_latency = 84 ,
. target_residency = 400 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
. enter = NULL }
} ;
static struct cpuidle_state ivt_cstates_8s [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2014-04-04 09:21:07 +04:00
. exit_latency = 1 ,
. target_residency = 1 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2014-04-04 09:21:07 +04:00
. exit_latency = 10 ,
. target_residency = 500 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-04-04 09:21:07 +04:00
. exit_latency = 59 ,
. target_residency = 600 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2014-04-04 09:21:07 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-04-04 09:21:07 +04:00
. exit_latency = 88 ,
. target_residency = 700 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-04-04 09:21:07 +04:00
{
. enter = NULL }
} ;
2014-01-09 11:30:26 +04:00
static struct cpuidle_state hsw_cstates [ ] = {
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2013-01-31 23:40:49 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2013-01-31 23:40:49 +04:00
. exit_latency = 2 ,
. target_residency = 2 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 10:31:56 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2013-02-02 10:31:56 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2013-02-02 10:31:56 +04:00
. exit_latency = 10 ,
. target_residency = 20 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2013-01-31 23:40:49 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-01-31 23:40:49 +04:00
. exit_latency = 33 ,
. target_residency = 100 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2013-01-31 23:40:49 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-01-31 23:40:49 +04:00
. exit_latency = 133 ,
. target_residency = 400 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C7s " ,
2013-01-31 23:40:49 +04:00
. desc = " MWAIT 0x32 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x32 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-01-31 23:40:49 +04:00
. exit_latency = 166 ,
. target_residency = 500 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-27 22:18:50 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C8 " ,
2013-02-27 22:18:50 +04:00
. desc = " MWAIT 0x40 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x40 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-02-27 22:18:50 +04:00
. exit_latency = 300 ,
. target_residency = 900 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-27 22:18:50 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C9 " ,
2013-02-27 22:18:50 +04:00
. desc = " MWAIT 0x50 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x50 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-02-27 22:18:50 +04:00
. exit_latency = 600 ,
. target_residency = 1800 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-27 22:18:50 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C10 " ,
2013-02-27 22:18:50 +04:00
. desc = " MWAIT 0x60 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-02-27 22:18:50 +04:00
. exit_latency = 2600 ,
. target_residency = 7700 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
. enter = NULL }
2013-01-31 23:40:49 +04:00
} ;
2014-02-05 08:56:40 +04:00
static struct cpuidle_state bdw_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2014-02-05 08:56:40 +04:00
. exit_latency = 2 ,
. target_residency = 2 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x01 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x01 ) ,
2014-02-05 08:56:40 +04:00
. exit_latency = 10 ,
. target_residency = 20 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-05 08:56:40 +04:00
. exit_latency = 40 ,
. target_residency = 100 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x20 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-05 08:56:40 +04:00
. exit_latency = 133 ,
. target_residency = 400 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C7s " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x32 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x32 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-05 08:56:40 +04:00
. exit_latency = 166 ,
. target_residency = 500 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C8 " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x40 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x40 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-05 08:56:40 +04:00
. exit_latency = 300 ,
. target_residency = 900 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C9 " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x50 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x50 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-05 08:56:40 +04:00
. exit_latency = 600 ,
. target_residency = 1800 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C10 " ,
2014-02-05 08:56:40 +04:00
. desc = " MWAIT 0x60 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2014-02-05 08:56:40 +04:00
. exit_latency = 2600 ,
. target_residency = 7700 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-02-05 08:56:40 +04:00
{
. enter = NULL }
} ;
2013-01-31 23:40:49 +04:00
2015-03-26 06:20:37 +03:00
static struct cpuidle_state skl_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 2 ,
. target_residency = 2 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x01 " ,
. flags = MWAIT2flg ( 0x01 ) ,
. exit_latency = 10 ,
. target_residency = 20 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C3 " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x10 " ,
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 70 ,
. target_residency = 100 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x20 " ,
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2015-09-09 20:35:05 +03:00
. exit_latency = 85 ,
2015-03-26 06:20:37 +03:00
. target_residency = 200 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C7s " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x33 " ,
. flags = MWAIT2flg ( 0x33 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 124 ,
. target_residency = 800 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C8 " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x40 " ,
. flags = MWAIT2flg ( 0x40 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2015-09-09 20:35:05 +03:00
. exit_latency = 200 ,
2015-03-26 06:20:37 +03:00
. target_residency = 800 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-09-09 20:35:05 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C9 " ,
2015-09-09 20:35:05 +03:00
. desc = " MWAIT 0x50 " ,
. flags = MWAIT2flg ( 0x50 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 480 ,
. target_residency = 5000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C10 " ,
2015-03-26 06:20:37 +03:00
. desc = " MWAIT 0x60 " ,
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 890 ,
. target_residency = 5000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2015-03-26 06:20:37 +03:00
{
. enter = NULL }
} ;
2016-04-07 00:00:58 +03:00
static struct cpuidle_state skx_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2016-04-07 00:00:58 +03:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 2 ,
. target_residency = 2 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:58 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2016-04-07 00:00:58 +03:00
. desc = " MWAIT 0x01 " ,
. flags = MWAIT2flg ( 0x01 ) ,
. exit_latency = 10 ,
. target_residency = 20 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:58 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2016-04-07 00:00:58 +03:00
. desc = " MWAIT 0x20 " ,
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 133 ,
. target_residency = 600 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:58 +03:00
{
. enter = NULL }
} ;
2014-01-09 11:30:26 +04:00
static struct cpuidle_state atom_cstates [ ] = {
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2010-03-08 22:07:30 +03:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2013-02-02 10:31:56 +04:00
. exit_latency = 10 ,
. target_residency = 20 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C2 " ,
2010-03-08 22:07:30 +03:00
. desc = " MWAIT 0x10 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x10 ) ,
2010-03-08 22:07:30 +03:00
. exit_latency = 20 ,
. target_residency = 80 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C4 " ,
2010-03-08 22:07:30 +03:00
. desc = " MWAIT 0x30 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x30 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-03-08 22:07:30 +03:00
. exit_latency = 100 ,
. target_residency = 400 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2010-10-05 21:43:14 +04:00
. desc = " MWAIT 0x52 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x52 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2010-10-05 21:43:14 +04:00
. exit_latency = 140 ,
. target_residency = 560 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-02-02 08:37:30 +04:00
{
. enter = NULL }
2010-03-08 22:07:30 +03:00
} ;
2016-10-25 17:11:39 +03:00
static struct cpuidle_state tangier_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2016-10-25 17:11:39 +03:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 1 ,
. target_residency = 4 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-10-25 17:11:39 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C4 " ,
2016-10-25 17:11:39 +03:00
. desc = " MWAIT 0x30 " ,
. flags = MWAIT2flg ( 0x30 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 100 ,
. target_residency = 400 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-10-25 17:11:39 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2016-10-25 17:11:39 +03:00
. desc = " MWAIT 0x52 " ,
. flags = MWAIT2flg ( 0x52 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 140 ,
. target_residency = 560 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-10-25 17:11:39 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C7 " ,
2016-10-25 17:11:39 +03:00
. desc = " MWAIT 0x60 " ,
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 1200 ,
. target_residency = 4000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-10-25 17:11:39 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C9 " ,
2016-10-25 17:11:39 +03:00
. desc = " MWAIT 0x64 " ,
. flags = MWAIT2flg ( 0x64 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 10000 ,
. target_residency = 20000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-10-25 17:11:39 +03:00
{
. enter = NULL }
} ;
2014-01-09 11:30:27 +04:00
static struct cpuidle_state avn_cstates [ ] = {
2013-11-09 09:30:17 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2013-11-09 09:30:17 +04:00
. desc = " MWAIT 0x00 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x00 ) ,
2013-11-09 09:30:17 +04:00
. exit_latency = 2 ,
. target_residency = 2 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2013-11-09 09:30:17 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2013-11-09 09:30:17 +04:00
. desc = " MWAIT 0x51 " ,
2014-11-12 18:03:50 +03:00
. flags = MWAIT2flg ( 0x51 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
2013-11-09 09:30:17 +04:00
. exit_latency = 15 ,
. target_residency = 45 ,
2015-02-11 07:04:17 +03:00
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2014-01-09 11:30:27 +04:00
{
. enter = NULL }
2013-11-09 09:30:17 +04:00
} ;
2014-09-05 04:22:54 +04:00
static struct cpuidle_state knl_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2014-09-05 04:22:54 +04:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 1 ,
. target_residency = 2 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle } ,
2014-09-05 04:22:54 +04:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2014-09-05 04:22:54 +04:00
. desc = " MWAIT 0x10 " ,
. flags = MWAIT2flg ( 0x10 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 120 ,
. target_residency = 500 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle } ,
2014-09-05 04:22:54 +04:00
{
. enter = NULL }
} ;
2010-03-08 22:07:30 +03:00
2016-04-07 00:00:47 +03:00
static struct cpuidle_state bxt_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 2 ,
. target_residency = 2 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x01 " ,
. flags = MWAIT2flg ( 0x01 ) ,
. exit_latency = 10 ,
. target_residency = 20 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x20 " ,
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 133 ,
. target_residency = 133 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C7s " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x31 " ,
. flags = MWAIT2flg ( 0x31 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 155 ,
. target_residency = 155 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C8 " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x40 " ,
. flags = MWAIT2flg ( 0x40 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 1000 ,
. target_residency = 1000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C9 " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x50 " ,
. flags = MWAIT2flg ( 0x50 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 2000 ,
. target_residency = 2000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C10 " ,
2016-04-07 00:00:47 +03:00
. desc = " MWAIT 0x60 " ,
. flags = MWAIT2flg ( 0x60 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 10000 ,
. target_residency = 10000 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-04-07 00:00:47 +03:00
{
. enter = NULL }
} ;
2016-06-17 08:28:34 +03:00
static struct cpuidle_state dnv_cstates [ ] = {
{
2017-03-01 00:32:44 +03:00
. name = " C1 " ,
2016-06-17 08:28:34 +03:00
. desc = " MWAIT 0x00 " ,
. flags = MWAIT2flg ( 0x00 ) ,
. exit_latency = 2 ,
. target_residency = 2 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-06-17 08:28:34 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C1E " ,
2016-06-17 08:28:34 +03:00
. desc = " MWAIT 0x01 " ,
. flags = MWAIT2flg ( 0x01 ) ,
. exit_latency = 10 ,
. target_residency = 20 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-06-17 08:28:34 +03:00
{
2017-03-01 00:32:44 +03:00
. name = " C6 " ,
2016-06-17 08:28:34 +03:00
. desc = " MWAIT 0x20 " ,
. flags = MWAIT2flg ( 0x20 ) | CPUIDLE_FLAG_TLB_FLUSHED ,
. exit_latency = 50 ,
. target_residency = 500 ,
. enter = & intel_idle ,
2017-08-10 01:14:45 +03:00
. enter_s2idle = intel_idle_s2idle , } ,
2016-06-17 08:28:34 +03:00
{
. enter = NULL }
} ;
2010-03-08 22:07:30 +03:00
/**
* intel_idle
* @ dev : cpuidle_device
2011-10-28 14:50:42 +04:00
* @ drv : cpuidle driver
2011-10-28 14:50:09 +04:00
* @ index : index of cpuidle state
2010-03-08 22:07:30 +03:00
*
2012-01-11 03:48:21 +04:00
* Must be called under local_irq_disable ( ) .
2010-03-08 22:07:30 +03:00
*/
2016-10-08 03:02:55 +03:00
static __cpuidle int intel_idle ( struct cpuidle_device * dev ,
struct cpuidle_driver * drv , int index )
2010-03-08 22:07:30 +03:00
{
unsigned long ecx = 1 ; /* break on interrupt flag */
2011-10-28 14:50:42 +04:00
struct cpuidle_state * state = & drv - > states [ index ] ;
2013-02-01 04:55:37 +04:00
unsigned long eax = flg2MWAIT ( state - > flags ) ;
2010-03-08 22:07:30 +03:00
unsigned int cstate ;
2017-10-06 20:19:45 +03:00
bool uninitialized_var ( tick ) ;
2017-11-04 14:16:12 +03:00
int cpu = smp_processor_id ( ) ;
2010-03-08 22:07:30 +03:00
2010-10-01 05:19:07 +04:00
/*
2017-11-04 14:16:12 +03:00
* leave_mm ( ) to avoid costly and often unnecessary wakeups
* for flushing the user TLB ' s associated with the active mm .
2010-10-01 05:19:07 +04:00
*/
2017-11-04 14:16:12 +03:00
if ( state - > flags & CPUIDLE_FLAG_TLB_FLUSHED )
leave_mm ( cpu ) ;
2010-10-01 05:19:07 +04:00
2017-10-06 20:19:45 +03:00
if ( ! static_cpu_has ( X86_FEATURE_ARAT ) ) {
cstate = ( ( ( eax ) > > MWAIT_SUBSTATE_SIZE ) &
MWAIT_CSTATE_MASK ) + 1 ;
tick = false ;
if ( ! ( lapic_timer_reliable_states & ( 1 < < ( cstate ) ) ) ) {
tick = true ;
tick_broadcast_enter ( ) ;
}
}
2010-03-08 22:07:30 +03:00
2013-12-12 18:08:36 +04:00
mwait_idle_with_hints ( eax , ecx ) ;
2010-03-08 22:07:30 +03:00
2017-10-06 20:19:45 +03:00
if ( ! static_cpu_has ( X86_FEATURE_ARAT ) & & tick )
2015-04-03 03:14:23 +03:00
tick_broadcast_exit ( ) ;
2010-03-08 22:07:30 +03:00
2011-10-28 14:50:09 +04:00
return index ;
2010-03-08 22:07:30 +03:00
}
2015-02-11 07:04:17 +03:00
/**
2017-08-10 01:14:45 +03:00
* intel_idle_s2idle - simplified " enter " callback routine for suspend - to - idle
2015-02-11 07:04:17 +03:00
* @ dev : cpuidle_device
* @ drv : cpuidle driver
* @ index : state index
*/
2017-08-10 01:14:45 +03:00
static void intel_idle_s2idle ( struct cpuidle_device * dev ,
2015-02-11 07:04:17 +03:00
struct cpuidle_driver * drv , int index )
{
unsigned long ecx = 1 ; /* break on interrupt flag */
unsigned long eax = flg2MWAIT ( drv - > states [ index ] . flags ) ;
mwait_idle_with_hints ( eax , ecx ) ;
}
2016-11-29 12:51:43 +03:00
static void __setup_broadcast_timer ( bool on )
2011-01-10 04:38:12 +03:00
{
2015-04-03 03:02:34 +03:00
if ( on )
tick_broadcast_enable ( ) ;
else
tick_broadcast_disable ( ) ;
2011-01-10 04:38:12 +03:00
}
2016-11-29 12:51:43 +03:00
static void auto_demotion_disable ( void )
2011-01-19 04:48:27 +03:00
{
unsigned long long msr_bits ;
2017-01-08 07:23:25 +03:00
rdmsrl ( MSR_PKG_CST_CONFIG_CONTROL , msr_bits ) ;
2012-01-26 03:09:07 +04:00
msr_bits & = ~ ( icpu - > auto_demotion_disable_flags ) ;
2017-01-08 07:23:25 +03:00
wrmsrl ( MSR_PKG_CST_CONFIG_CONTROL , msr_bits ) ;
2011-01-19 04:48:27 +03:00
}
2016-11-29 12:51:43 +03:00
static void c1e_promotion_disable ( void )
2013-02-02 10:31:56 +04:00
{
unsigned long long msr_bits ;
rdmsrl ( MSR_IA32_POWER_CTL , msr_bits ) ;
msr_bits & = ~ 0x2 ;
wrmsrl ( MSR_IA32_POWER_CTL , msr_bits ) ;
}
2011-01-19 04:48:27 +03:00
2012-01-26 03:09:07 +04:00
static const struct idle_cpu idle_cpu_nehalem = {
. state_table = nehalem_cstates ,
. auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE ,
2013-02-02 10:31:56 +04:00
. disable_promotion_to_c1e = true ,
2012-01-26 03:09:07 +04:00
} ;
static const struct idle_cpu idle_cpu_atom = {
. state_table = atom_cstates ,
} ;
2016-10-25 17:11:39 +03:00
static const struct idle_cpu idle_cpu_tangier = {
. state_table = tangier_cstates ,
} ;
2012-01-26 03:09:07 +04:00
static const struct idle_cpu idle_cpu_lincroft = {
. state_table = atom_cstates ,
. auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE ,
} ;
static const struct idle_cpu idle_cpu_snb = {
. state_table = snb_cstates ,
2013-02-02 10:31:56 +04:00
. disable_promotion_to_c1e = true ,
2012-01-26 03:09:07 +04:00
} ;
2014-02-14 11:30:00 +04:00
static const struct idle_cpu idle_cpu_byt = {
. state_table = byt_cstates ,
. disable_promotion_to_c1e = true ,
2014-07-31 23:21:24 +04:00
. byt_auto_demotion_disable_flag = true ,
2014-02-14 11:30:00 +04:00
} ;
2015-03-28 03:54:01 +03:00
static const struct idle_cpu idle_cpu_cht = {
. state_table = cht_cstates ,
. disable_promotion_to_c1e = true ,
. byt_auto_demotion_disable_flag = true ,
} ;
2012-06-02 03:45:32 +04:00
static const struct idle_cpu idle_cpu_ivb = {
. state_table = ivb_cstates ,
2013-02-02 10:31:56 +04:00
. disable_promotion_to_c1e = true ,
2012-06-02 03:45:32 +04:00
} ;
2014-04-04 09:21:07 +04:00
static const struct idle_cpu idle_cpu_ivt = {
. state_table = ivt_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2013-01-31 23:40:49 +04:00
static const struct idle_cpu idle_cpu_hsw = {
. state_table = hsw_cstates ,
2013-02-02 10:31:56 +04:00
. disable_promotion_to_c1e = true ,
2013-01-31 23:40:49 +04:00
} ;
2014-02-05 08:56:40 +04:00
static const struct idle_cpu idle_cpu_bdw = {
. state_table = bdw_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2015-03-26 06:20:37 +03:00
static const struct idle_cpu idle_cpu_skl = {
. state_table = skl_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2016-04-07 00:00:58 +03:00
static const struct idle_cpu idle_cpu_skx = {
. state_table = skx_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2015-03-26 06:20:37 +03:00
2013-11-09 09:30:17 +04:00
static const struct idle_cpu idle_cpu_avn = {
. state_table = avn_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2014-09-05 04:22:54 +04:00
static const struct idle_cpu idle_cpu_knl = {
. state_table = knl_cstates ,
} ;
2016-04-07 00:00:47 +03:00
static const struct idle_cpu idle_cpu_bxt = {
. state_table = bxt_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2016-06-17 08:28:34 +03:00
static const struct idle_cpu idle_cpu_dnv = {
. state_table = dnv_cstates ,
. disable_promotion_to_c1e = true ,
} ;
2012-01-26 03:09:07 +04:00
# define ICPU(model, cpu) \
2017-11-09 10:19:39 +03:00
{ X86_VENDOR_INTEL , 6 , model , X86_FEATURE_ANY , ( unsigned long ) & cpu }
2012-01-26 03:09:07 +04:00
2015-03-26 00:15:14 +03:00
static const struct x86_cpu_id intel_idle_ids [ ] __initconst = {
2016-06-03 03:19:32 +03:00
ICPU ( INTEL_FAM6_NEHALEM_EP , idle_cpu_nehalem ) ,
ICPU ( INTEL_FAM6_NEHALEM , idle_cpu_nehalem ) ,
2016-06-29 22:27:37 +03:00
ICPU ( INTEL_FAM6_NEHALEM_G , idle_cpu_nehalem ) ,
2016-06-03 03:19:32 +03:00
ICPU ( INTEL_FAM6_WESTMERE , idle_cpu_nehalem ) ,
ICPU ( INTEL_FAM6_WESTMERE_EP , idle_cpu_nehalem ) ,
ICPU ( INTEL_FAM6_NEHALEM_EX , idle_cpu_nehalem ) ,
ICPU ( INTEL_FAM6_ATOM_PINEVIEW , idle_cpu_atom ) ,
ICPU ( INTEL_FAM6_ATOM_LINCROFT , idle_cpu_lincroft ) ,
ICPU ( INTEL_FAM6_WESTMERE_EX , idle_cpu_nehalem ) ,
ICPU ( INTEL_FAM6_SANDYBRIDGE , idle_cpu_snb ) ,
ICPU ( INTEL_FAM6_SANDYBRIDGE_X , idle_cpu_snb ) ,
ICPU ( INTEL_FAM6_ATOM_CEDARVIEW , idle_cpu_atom ) ,
ICPU ( INTEL_FAM6_ATOM_SILVERMONT1 , idle_cpu_byt ) ,
2016-10-25 17:11:39 +03:00
ICPU ( INTEL_FAM6_ATOM_MERRIFIELD , idle_cpu_tangier ) ,
2016-06-03 03:19:32 +03:00
ICPU ( INTEL_FAM6_ATOM_AIRMONT , idle_cpu_cht ) ,
ICPU ( INTEL_FAM6_IVYBRIDGE , idle_cpu_ivb ) ,
ICPU ( INTEL_FAM6_IVYBRIDGE_X , idle_cpu_ivt ) ,
ICPU ( INTEL_FAM6_HASWELL_CORE , idle_cpu_hsw ) ,
ICPU ( INTEL_FAM6_HASWELL_X , idle_cpu_hsw ) ,
ICPU ( INTEL_FAM6_HASWELL_ULT , idle_cpu_hsw ) ,
ICPU ( INTEL_FAM6_HASWELL_GT3E , idle_cpu_hsw ) ,
ICPU ( INTEL_FAM6_ATOM_SILVERMONT2 , idle_cpu_avn ) ,
ICPU ( INTEL_FAM6_BROADWELL_CORE , idle_cpu_bdw ) ,
ICPU ( INTEL_FAM6_BROADWELL_GT3E , idle_cpu_bdw ) ,
ICPU ( INTEL_FAM6_BROADWELL_X , idle_cpu_bdw ) ,
ICPU ( INTEL_FAM6_BROADWELL_XEON_D , idle_cpu_bdw ) ,
ICPU ( INTEL_FAM6_SKYLAKE_MOBILE , idle_cpu_skl ) ,
ICPU ( INTEL_FAM6_SKYLAKE_DESKTOP , idle_cpu_skl ) ,
ICPU ( INTEL_FAM6_KABYLAKE_MOBILE , idle_cpu_skl ) ,
ICPU ( INTEL_FAM6_KABYLAKE_DESKTOP , idle_cpu_skl ) ,
ICPU ( INTEL_FAM6_SKYLAKE_X , idle_cpu_skx ) ,
ICPU ( INTEL_FAM6_XEON_PHI_KNL , idle_cpu_knl ) ,
2016-10-13 18:30:58 +03:00
ICPU ( INTEL_FAM6_XEON_PHI_KNM , idle_cpu_knl ) ,
2016-06-03 03:19:32 +03:00
ICPU ( INTEL_FAM6_ATOM_GOLDMONT , idle_cpu_bxt ) ,
2017-04-23 09:06:25 +03:00
ICPU ( INTEL_FAM6_ATOM_GEMINI_LAKE , idle_cpu_bxt ) ,
2016-06-17 08:28:34 +03:00
ICPU ( INTEL_FAM6_ATOM_DENVERTON , idle_cpu_dnv ) ,
2012-01-26 03:09:07 +04:00
{ }
} ;
2010-03-08 22:07:30 +03:00
/*
* intel_idle_probe ( )
*/
2013-08-30 14:27:45 +04:00
static int __init intel_idle_probe ( void )
2010-03-08 22:07:30 +03:00
{
2010-05-28 10:22:03 +04:00
unsigned int eax , ebx , ecx ;
2012-01-26 03:09:07 +04:00
const struct x86_cpu_id * id ;
2010-03-08 22:07:30 +03:00
if ( max_cstate = = 0 ) {
2017-06-09 22:29:20 +03:00
pr_debug ( " disabled \n " ) ;
2010-03-08 22:07:30 +03:00
return - EPERM ;
}
2012-01-26 03:09:07 +04:00
id = x86_match_cpu ( intel_idle_ids ) ;
if ( ! id ) {
if ( boot_cpu_data . x86_vendor = = X86_VENDOR_INTEL & &
boot_cpu_data . x86 = = 6 )
2017-06-09 22:29:20 +03:00
pr_debug ( " does not run on family %d model %d \n " ,
boot_cpu_data . x86 , boot_cpu_data . x86_model ) ;
2010-03-08 22:07:30 +03:00
return - ENODEV ;
2012-01-26 03:09:07 +04:00
}
2010-03-08 22:07:30 +03:00
2017-11-09 10:19:39 +03:00
if ( ! boot_cpu_has ( X86_FEATURE_MWAIT ) ) {
pr_debug ( " Please enable MWAIT in BIOS SETUP \n " ) ;
return - ENODEV ;
}
2010-03-08 22:07:30 +03:00
if ( boot_cpu_data . cpuid_level < CPUID_MWAIT_LEAF )
return - ENODEV ;
2010-05-28 10:22:03 +04:00
cpuid ( CPUID_MWAIT_LEAF , & eax , & ebx , & ecx , & mwait_substates ) ;
2010-03-08 22:07:30 +03:00
if ( ! ( ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED ) | |
2011-12-05 01:17:29 +04:00
! ( ecx & CPUID5_ECX_INTERRUPT_BREAK ) | |
! mwait_substates )
2010-03-08 22:07:30 +03:00
return - ENODEV ;
2017-06-09 22:29:20 +03:00
pr_debug ( " MWAIT substates: 0x%x \n " , mwait_substates ) ;
2010-03-08 22:07:30 +03:00
2012-01-26 03:09:07 +04:00
icpu = ( const struct idle_cpu * ) id - > driver_data ;
cpuidle_state_table = icpu - > state_table ;
2010-03-08 22:07:30 +03:00
2017-06-09 22:29:20 +03:00
pr_debug ( " v " INTEL_IDLE_VERSION " model 0x%X \n " ,
boot_cpu_data . x86_model ) ;
2010-03-08 22:07:30 +03:00
return 0 ;
}
/*
* intel_idle_cpuidle_devices_uninit ( )
2016-04-07 00:00:53 +03:00
* Unregisters the cpuidle devices .
2010-03-08 22:07:30 +03:00
*/
static void intel_idle_cpuidle_devices_uninit ( void )
{
int i ;
struct cpuidle_device * dev ;
for_each_online_cpu ( i ) {
dev = per_cpu_ptr ( intel_idle_cpuidle_devices , i ) ;
cpuidle_unregister_device ( dev ) ;
}
}
2014-04-04 09:21:07 +04:00
/*
2016-03-13 08:33:48 +03:00
* ivt_idle_state_table_update ( void )
2014-04-04 09:21:07 +04:00
*
2016-03-13 08:33:48 +03:00
* Tune IVT multi - socket targets
2014-04-04 09:21:07 +04:00
* Assumption : num_sockets = = ( max_package_num + 1 )
*/
2016-03-13 08:33:48 +03:00
static void ivt_idle_state_table_update ( void )
2014-04-04 09:21:07 +04:00
{
/* IVT uses a different table for 1-2, 3-4, and > 4 sockets */
2016-03-13 08:33:48 +03:00
int cpu , package_num , num_sockets = 1 ;
for_each_online_cpu ( cpu ) {
package_num = topology_physical_package_id ( cpu ) ;
if ( package_num + 1 > num_sockets ) {
num_sockets = package_num + 1 ;
if ( num_sockets > 4 ) {
cpuidle_state_table = ivt_cstates_8s ;
return ;
2014-04-04 09:21:07 +04:00
}
}
2016-03-13 08:33:48 +03:00
}
if ( num_sockets > 2 )
cpuidle_state_table = ivt_cstates_4s ;
/* else, 1 and 2 socket systems use default ivt_cstates */
}
2016-04-07 00:00:47 +03:00
/*
* Translate IRTL ( Interrupt Response Time Limit ) MSR to usec
*/
static unsigned int irtl_ns_units [ ] = {
1 , 32 , 1024 , 32768 , 1048576 , 33554432 , 0 , 0 } ;
static unsigned long long irtl_2_usec ( unsigned long long irtl )
{
unsigned long long ns ;
2016-06-27 09:35:12 +03:00
if ( ! irtl )
return 0 ;
2016-06-27 09:35:48 +03:00
ns = irtl_ns_units [ ( irtl > > 10 ) & 0x7 ] ;
2016-04-07 00:00:47 +03:00
return div64_u64 ( ( irtl & 0x3FF ) * ns , 1000 ) ;
}
/*
* bxt_idle_state_table_update ( void )
*
* On BXT , we trust the IRTL to show the definitive maximum latency
* We use the same value for target_residency .
*/
static void bxt_idle_state_table_update ( void )
{
unsigned long long msr ;
2016-06-27 09:35:12 +03:00
unsigned int usec ;
2016-04-07 00:00:47 +03:00
rdmsrl ( MSR_PKGC6_IRTL , msr ) ;
2016-06-27 09:35:12 +03:00
usec = irtl_2_usec ( msr ) ;
if ( usec ) {
2016-04-07 00:00:47 +03:00
bxt_cstates [ 2 ] . exit_latency = usec ;
bxt_cstates [ 2 ] . target_residency = usec ;
}
rdmsrl ( MSR_PKGC7_IRTL , msr ) ;
2016-06-27 09:35:12 +03:00
usec = irtl_2_usec ( msr ) ;
if ( usec ) {
2016-04-07 00:00:47 +03:00
bxt_cstates [ 3 ] . exit_latency = usec ;
bxt_cstates [ 3 ] . target_residency = usec ;
}
rdmsrl ( MSR_PKGC8_IRTL , msr ) ;
2016-06-27 09:35:12 +03:00
usec = irtl_2_usec ( msr ) ;
if ( usec ) {
2016-04-07 00:00:47 +03:00
bxt_cstates [ 4 ] . exit_latency = usec ;
bxt_cstates [ 4 ] . target_residency = usec ;
}
rdmsrl ( MSR_PKGC9_IRTL , msr ) ;
2016-06-27 09:35:12 +03:00
usec = irtl_2_usec ( msr ) ;
if ( usec ) {
2016-04-07 00:00:47 +03:00
bxt_cstates [ 5 ] . exit_latency = usec ;
bxt_cstates [ 5 ] . target_residency = usec ;
}
rdmsrl ( MSR_PKGC10_IRTL , msr ) ;
2016-06-27 09:35:12 +03:00
usec = irtl_2_usec ( msr ) ;
if ( usec ) {
2016-04-07 00:00:47 +03:00
bxt_cstates [ 6 ] . exit_latency = usec ;
bxt_cstates [ 6 ] . target_residency = usec ;
}
}
2016-03-13 08:33:48 +03:00
/*
* sklh_idle_state_table_update ( void )
*
* On SKL - H ( model 0x5e ) disable C8 and C9 if :
* C10 is enabled and SGX disabled
*/
static void sklh_idle_state_table_update ( void )
{
unsigned long long msr ;
unsigned int eax , ebx , ecx , edx ;
/* if PC10 disabled via cmdline intel_idle.max_cstate=7 or shallower */
if ( max_cstate < = 7 )
return ;
/* if PC10 not present in CPUID.MWAIT.EDX */
if ( ( mwait_substates & ( 0xF < < 28 ) ) = = 0 )
return ;
2017-01-08 07:23:25 +03:00
rdmsrl ( MSR_PKG_CST_CONFIG_CONTROL , msr ) ;
2016-03-13 08:33:48 +03:00
/* PC10 is not enabled in PKG C-state limit */
if ( ( msr & 0xF ) ! = 8 )
return ;
ecx = 0 ;
cpuid ( 7 , & eax , & ebx , & ecx , & edx ) ;
/* if SGX is present */
if ( ebx & ( 1 < < 2 ) ) {
2014-04-04 09:21:07 +04:00
2016-03-13 08:33:48 +03:00
rdmsrl ( MSR_IA32_FEATURE_CONTROL , msr ) ;
/* if SGX is enabled */
if ( msr & ( 1 < < 18 ) )
return ;
}
skl_cstates [ 5 ] . disabled = 1 ; /* C8-SKL */
skl_cstates [ 6 ] . disabled = 1 ; /* C9-SKL */
}
/*
* intel_idle_state_table_update ( )
*
* Update the default state_table for this CPU - id
*/
static void intel_idle_state_table_update ( void )
{
switch ( boot_cpu_data . x86_model ) {
2016-06-03 03:19:32 +03:00
case INTEL_FAM6_IVYBRIDGE_X :
2016-03-13 08:33:48 +03:00
ivt_idle_state_table_update ( ) ;
break ;
2016-06-03 03:19:32 +03:00
case INTEL_FAM6_ATOM_GOLDMONT :
2017-04-23 09:06:25 +03:00
case INTEL_FAM6_ATOM_GEMINI_LAKE :
2016-04-07 00:00:47 +03:00
bxt_idle_state_table_update ( ) ;
break ;
2016-06-03 03:19:32 +03:00
case INTEL_FAM6_SKYLAKE_DESKTOP :
2016-03-13 08:33:48 +03:00
sklh_idle_state_table_update ( ) ;
break ;
2014-04-04 09:21:07 +04:00
}
}
2011-10-28 14:50:42 +04:00
/*
* intel_idle_cpuidle_driver_init ( )
* allocate , initialize cpuidle_states
*/
2016-04-07 00:00:49 +03:00
static void __init intel_idle_cpuidle_driver_init ( void )
2011-10-28 14:50:42 +04:00
{
int cstate ;
struct cpuidle_driver * drv = & intel_idle_driver ;
2014-04-04 09:21:07 +04:00
intel_idle_state_table_update ( ) ;
2017-08-29 04:14:37 +03:00
cpuidle_poll_state_init ( drv ) ;
2011-10-28 14:50:42 +04:00
drv - > state_count = 1 ;
2013-02-02 08:37:30 +04:00
for ( cstate = 0 ; cstate < CPUIDLE_STATE_MAX ; + + cstate ) {
2014-02-14 09:50:34 +04:00
int num_substates , mwait_hint , mwait_cstate ;
2011-10-28 14:50:42 +04:00
2015-05-28 00:11:37 +03:00
if ( ( cpuidle_state_table [ cstate ] . enter = = NULL ) & &
2017-08-10 01:14:45 +03:00
( cpuidle_state_table [ cstate ] . enter_s2idle = = NULL ) )
2013-02-02 08:37:30 +04:00
break ;
if ( cstate + 1 > max_cstate ) {
2017-06-09 22:29:20 +03:00
pr_info ( " max_cstate %d reached \n " , max_cstate ) ;
2011-10-28 14:50:42 +04:00
break ;
}
2013-02-02 08:37:30 +04:00
mwait_hint = flg2MWAIT ( cpuidle_state_table [ cstate ] . flags ) ;
mwait_cstate = MWAIT_HINT2CSTATE ( mwait_hint ) ;
2014-02-14 09:50:34 +04:00
/* number of sub-states for this state in CPUID.MWAIT */
2013-02-02 08:37:30 +04:00
num_substates = ( mwait_substates > > ( ( mwait_cstate + 1 ) * 4 ) )
2011-10-28 14:50:42 +04:00
& MWAIT_SUBSTATE_MASK ;
2013-02-02 08:37:30 +04:00
2014-02-14 09:50:34 +04:00
/* if NO sub-states for this state in CPUID, skip it */
if ( num_substates = = 0 )
2011-10-28 14:50:42 +04:00
continue ;
2016-03-13 08:33:48 +03:00
/* if state marked as disabled, skip it */
if ( cpuidle_state_table [ cstate ] . disabled ! = 0 ) {
2017-06-09 22:29:20 +03:00
pr_debug ( " state %s is disabled \n " ,
cpuidle_state_table [ cstate ] . name ) ;
2016-03-13 08:33:48 +03:00
continue ;
}
2013-02-02 08:37:30 +04:00
if ( ( ( mwait_cstate + 1 ) > 2 ) & &
2011-10-28 14:50:42 +04:00
! boot_cpu_has ( X86_FEATURE_NONSTOP_TSC ) )
mark_tsc_unstable ( " TSC halts in idle "
" states deeper than C2 " ) ;
drv - > states [ drv - > state_count ] = /* structure copy */
cpuidle_state_table [ cstate ] ;
drv - > state_count + = 1 ;
}
2014-07-31 23:21:24 +04:00
if ( icpu - > byt_auto_demotion_disable_flag ) {
wrmsrl ( MSR_CC6_DEMOTION_POLICY_CONFIG , 0 ) ;
wrmsrl ( MSR_MC6_DEMOTION_POLICY_CONFIG , 0 ) ;
}
2011-10-28 14:50:42 +04:00
}
2010-03-08 22:07:30 +03:00
/*
2012-01-18 01:40:08 +04:00
* intel_idle_cpu_init ( )
2010-03-08 22:07:30 +03:00
* allocate , initialize , register cpuidle_devices
2012-01-18 01:40:08 +04:00
* @ cpu : cpu / core to initialize
2010-03-08 22:07:30 +03:00
*/
2016-11-29 12:51:43 +03:00
static int intel_idle_cpu_init ( unsigned int cpu )
2010-03-08 22:07:30 +03:00
{
struct cpuidle_device * dev ;
2012-01-18 01:40:08 +04:00
dev = per_cpu_ptr ( intel_idle_cpuidle_devices , cpu ) ;
dev - > cpu = cpu ;
2010-03-08 22:07:30 +03:00
2012-01-18 01:40:08 +04:00
if ( cpuidle_register_device ( dev ) ) {
2017-06-09 22:29:20 +03:00
pr_debug ( " cpuidle_register_device %d failed! \n " , cpu ) ;
2012-01-18 01:40:08 +04:00
return - EIO ;
2010-03-08 22:07:30 +03:00
}
2012-01-26 03:09:07 +04:00
if ( icpu - > auto_demotion_disable_flags )
2016-11-29 12:51:43 +03:00
auto_demotion_disable ( ) ;
2012-01-18 01:40:08 +04:00
2013-12-20 22:47:28 +04:00
if ( icpu - > disable_promotion_to_c1e )
2016-11-29 12:51:43 +03:00
c1e_promotion_disable ( ) ;
return 0 ;
}
static int intel_idle_cpu_online ( unsigned int cpu )
{
struct cpuidle_device * dev ;
if ( lapic_timer_reliable_states ! = LAPIC_TIMER_ALWAYS_RELIABLE )
__setup_broadcast_timer ( true ) ;
/*
* Some systems can hotplug a cpu at runtime after
* the kernel has booted , we have to initialize the
* driver in this case
*/
dev = per_cpu_ptr ( intel_idle_cpuidle_devices , cpu ) ;
if ( ! dev - > registered )
return intel_idle_cpu_init ( cpu ) ;
2013-12-20 22:47:28 +04:00
2010-03-08 22:07:30 +03:00
return 0 ;
}
static int __init intel_idle_init ( void )
{
2016-11-29 12:51:43 +03:00
int retval ;
2010-03-08 22:07:30 +03:00
2010-11-03 19:06:14 +03:00
/* Do not load intel_idle at all for now if idle= is passed */
if ( boot_option_idle_override ! = IDLE_NO_OVERRIDE )
return - ENODEV ;
2010-03-08 22:07:30 +03:00
retval = intel_idle_probe ( ) ;
if ( retval )
return retval ;
2016-04-07 00:00:52 +03:00
intel_idle_cpuidle_devices = alloc_percpu ( struct cpuidle_device ) ;
if ( intel_idle_cpuidle_devices = = NULL )
return - ENOMEM ;
2011-10-28 14:50:42 +04:00
intel_idle_cpuidle_driver_init ( ) ;
2010-03-08 22:07:30 +03:00
retval = cpuidle_register_driver ( & intel_idle_driver ) ;
if ( retval ) {
2012-08-17 00:06:55 +04:00
struct cpuidle_driver * drv = cpuidle_get_driver ( ) ;
2017-06-09 22:29:20 +03:00
printk ( KERN_DEBUG pr_fmt ( " intel_idle yielding to %s \n " ) ,
drv ? drv - > name : " none " ) ;
2016-11-29 12:51:43 +03:00
goto init_driver_fail ;
2010-03-08 22:07:30 +03:00
}
2016-04-07 00:00:54 +03:00
if ( boot_cpu_has ( X86_FEATURE_ARAT ) ) /* Always Reliable APIC Timer */
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE ;
2016-11-29 12:51:43 +03:00
retval = cpuhp_setup_state ( CPUHP_AP_ONLINE_DYN , " idle/intel:online " ,
intel_idle_cpu_online , NULL ) ;
if ( retval < 0 )
goto hp_setup_fail ;
2010-03-08 22:07:30 +03:00
2017-06-09 22:29:20 +03:00
pr_debug ( " lapic_timer_reliable_states 0x%x \n " ,
lapic_timer_reliable_states ) ;
2016-04-07 00:00:54 +03:00
2010-03-08 22:07:30 +03:00
return 0 ;
2016-11-29 12:51:43 +03:00
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 ;
2010-03-08 22:07:30 +03:00
}
2016-06-17 08:28:33 +03:00
device_initcall ( intel_idle_init ) ;
2010-03-08 22:07:30 +03:00
2016-06-17 08:28:33 +03:00
/*
* 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
* it at / sys / module / intel_idle / parameters / max_cstate - - so using module_param
* is the easiest way ( currently ) to continue doing that .
*/
2010-03-08 22:07:30 +03:00
module_param ( max_cstate , int , 0444 ) ;