// SPDX-License-Identifier: GPL-2.0/* * Copyright (c) 2009-2010 Intel Corporation * * Authors: * Jesse Barnes <jbarnes@virtuousgeek.org> */ /* * Some Intel Ibex Peak based platforms support so-called "intelligent * power sharing", which allows the CPU and GPU to cooperate to maximize * performance within a given TDP (thermal design point). This driver * performs the coordination between the CPU and GPU, monitors thermal and * power statistics in the platform, and initializes power monitoring * hardware. It also provides a few tunables to control behavior. Its * primary purpose is to safely allow CPU and GPU turbo modes to be enabled * by tracking power and thermal budget; secondarily it can boost turbo * performance by allocating more power or thermal budget to the CPU or GPU * based on available headroom and activity. * * The basic algorithm is driven by a 5s moving average of temperature. If * thermal headroom is available, the CPU and/or GPU power clamps may be * adjusted upwards. If we hit the thermal ceiling or a thermal trigger, * we scale back the clamp. Aside from trigger events (when we're critically * close or over our TDP) we don't adjust the clamps more than once every * five seconds. * * The thermal device (device 31, function 6) has a set of registers that * are updated by the ME firmware. The ME should also take the clamp values * written to those registers and write them to the CPU, but we currently * bypass that functionality and write the CPU MSR directly. * * UNSUPPORTED: * - dual MCP configs * * TODO: * - handle CPU hotplug * - provide turbo enable/disable api * * Related documents: * - CDI 403777, 403778 - Auburndale EDS vol 1 & 2 * - CDI 401376 - Ibex Peak EDS * - ref 26037, 26641 - IPS BIOS spec * - ref 26489 - Nehalem BIOS writer's guide * - ref 26921 - Ibex Peak BIOS Specification */ #include <linux/debugfs.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/sched.h>#include <linux/sched/loadavg.h>#include <linux/seq_file.h>#include <linux/string.h>#include <linux/tick.h>#include <linux/timer.h>#include <linux/dmi.h>#include <drm/intel/i915_drm.h>#include <asm/msr.h>#include <asm/processor.h>#include <asm/cpu_device_id.h>#include "intel_ips.h" #include <linux/io-64-nonatomic-lo-hi.h> #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32 /* * Package level MSRs for monitor/control */#define PLATFORM_INFO 0xce#define PLATFORM_TDP (1<<29)#define PLATFORM_RATIO (1<<28) #define IA32_MISC_ENABLE 0x1a0#define IA32_MISC_TURBO_EN (1ULL<<38) #define TURBO_POWER_CURRENT_LIMIT 0x1ac#define TURBO_TDC_OVR_EN (1UL<<31)#define TURBO_TDC_MASK (0x000000007fff0000UL)#define TURBO_TDC_SHIFT (16)#define TURBO_TDP_OVR_EN (1UL<<15)#define TURBO_TDP_MASK (0x0000000000003fffUL) /* * Core/thread MSRs for monitoring */#define IA32_PERF_CTL 0x199#define IA32_PERF_TURBO_DIS (1ULL<<32) /* * Thermal PCI device regs */#define THM_CFG_TBAR 0x10#define THM_CFG_TBAR_HI 0x14 #define THM_TSIU 0x00#define THM_TSE 0x01#define TSE_EN 0xb8#define THM_TSS 0x02#define THM_TSTR 0x03#define THM_TSTTP 0x04#define THM_TSCO 0x08#define THM_TSES 0x0c#define THM_TSGPEN 0x0d#define TSGPEN_HOT_LOHI (1<<1)#define TSGPEN_CRIT_LOHI (1<<2)#define THM_TSPC 0x0e#define THM_PPEC 0x10#define THM_CTA 0x12#define THM_PTA 0x14#define PTA_SLOPE_MASK (0xff00)#define PTA_SLOPE_SHIFT 8#define PTA_OFFSET_MASK (0x00ff)#define THM_MGTA 0x16#define MGTA_SLOPE_MASK (0xff00)#define MGTA_SLOPE_SHIFT 8#define MGTA_OFFSET_MASK (0x00ff)#define THM_TRC 0x1a#define TRC_CORE2_EN (1<<15)#define TRC_THM_EN (1<<12)#define TRC_C6_WAR (1<<8)#define TRC_CORE1_EN (1<<7)#define TRC_CORE_PWR (1<<6)#define TRC_PCH_EN (1<<5)#define TRC_MCH_EN (1<<4)#define TRC_DIMM4 (1<<3)#define TRC_DIMM3 (1<<2)#define TRC_DIMM2 (1<<1)#define TRC_DIMM1 (1<<0)#define THM_TES 0x20#define THM_TEN 0x21#define TEN_UPDATE_EN 1#define THM_PSC 0x24#define PSC_NTG (1<<0) /* No GFX turbo support */#define PSC_NTPC (1<<1) /* No CPU turbo support */#define PSC_PP_DEF (0<<2) /* Perf policy up to driver */#define PSP_PP_PC (1<<2) /* BIOS prefers CPU perf */#define PSP_PP_BAL (2<<2) /* BIOS wants balanced perf */#define PSP_PP_GFX (3<<2) /* BIOS prefers GFX perf */#define PSP_PBRT (1<<4) /* BIOS run time support */#define THM_CTV1 0x30#define CTV_TEMP_ERROR (1<<15)#define CTV_TEMP_MASK 0x3f#define CTV_#define THM_CTV2 0x32#define THM_CEC 0x34 /* undocumented power accumulator in joules */#define THM_AE 0x3f#define THM_HTS 0x50 /* 32 bits */#define HTS_PCPL_MASK (0x7fe00000)#define HTS_PCPL_SHIFT 21#define HTS_GPL_MASK (0x001ff000)#define HTS_GPL_SHIFT 12#define HTS_PP_MASK (0x00000c00)#define HTS_PP_SHIFT 10#define HTS_PP_DEF 0#define HTS_PP_PROC 1#define HTS_PP_BAL 2#define HTS_PP_GFX 3#define HTS_PCTD_DIS (1<<9)#define HTS_GTD_DIS (1<<8)#define HTS_PTL_MASK (0x000000fe)#define HTS_PTL_SHIFT 1#define HTS_NVV (1<<0)#define THM_HTSHI 0x54 /* 16 bits */#define HTS2_PPL_MASK (0x03ff)#define HTS2_PRST_MASK (0x3c00)#define HTS2_PRST_SHIFT 10#define HTS2_PRST_UNLOADED 0#define HTS2_PRST_RUNNING 1#define HTS2_PRST_TDISOP 2 /* turbo disabled due to power */#define HTS2_PRST_TDISHT 3 /* turbo disabled due to high temp */#define HTS2_PRST_TDISUSR 4 /* user disabled turbo */#define HTS2_PRST_TDISPLAT 5 /* platform disabled turbo */#define HTS2_PRST_TDISPM 6 /* power management disabled turbo */#define HTS2_PRST_TDISERR 7 /* some kind of error disabled turbo */#define THM_PTL 0x56#define THM_MGTV 0x58#define TV_MASK 0x000000000000ff00#define TV_SHIFT 8#define THM_PTV 0x60#define PTV_MASK 0x00ff#define THM_MMGPC 0x64#define THM_MPPC 0x66#define THM_MPCPC 0x68#define THM_TSPIEN 0x82#define TSPIEN_AUX_LOHI (1<<0)#define TSPIEN_HOT_LOHI (1<<1)#define TSPIEN_CRIT_LOHI (1<<2)#define TSPIEN_AUX2_LOHI (1<<3)#define THM_TSLOCK 0x83#define THM_ATR 0x84#define THM_TOF 0x87#define THM_STS 0x98#define STS_PCPL_MASK (0x7fe00000)#define STS_PCPL_SHIFT 21#define STS_GPL_MASK (0x001ff000)#define STS_GPL_SHIFT 12#define STS_PP_MASK (0x00000c00)#define STS_PP_SHIFT 10#define STS_PP_DEF 0#define STS_PP_PROC 1#define STS_PP_BAL 2#define STS_PP_GFX 3#define STS_PCTD_DIS (1<<9)#define STS_GTD_DIS (1<<8)#define STS_PTL_MASK (0x000000fe)#define STS_PTL_SHIFT 1#define STS_NVV (1<<0)#define THM_SEC 0x9c#define SEC_ACK (1<<0)#define THM_TC3 0xa4#define THM_TC1 0xa8#define STS_PPL_MASK (0x0003ff00)#define STS_PPL_SHIFT 16#define THM_TC2 0xac#define THM_DTV 0xb0#define THM_ITV 0xd8#define ITV_ME_SEQNO_MASK 0x00ff0000 /* ME should update every ~200ms */#define ITV_ME_SEQNO_SHIFT (16)#define ITV_MCH_TEMP_MASK 0x0000ff00#define ITV_MCH_TEMP_SHIFT (8)#define ITV_PCH_TEMP_MASK 0x000000ff #define thm_readb(off) readb(ips->regmap + (off))#define thm_readw(off) readw(ips->regmap + (off))#define thm_readl(off) readl(ips->regmap + (off))#define thm_readq(off) readq(ips->regmap + (off)) #define thm_writeb(off, val) writeb((val), ips->regmap + (off))#define thm_writew(off, val) writew((val), ips->regmap + (off))#define thm_writel(off, val) writel((val), ips->regmap + (off)) static const int IPS_ADJUST_PERIOD = 5000; /* ms */static bool late_i915_load = false; /* For initial average collection */static const int IPS_SAMPLE_PERIOD = 200; /* ms */static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */#define IPS_SAMPLE_COUNT (IPS_SAMPLE_WINDOW / IPS_SAMPLE_PERIOD) /* Per-SKU limits */struct ips_mcp_limits { int mcp_power_limit; /* mW units */ int core_power_limit; int mch_power_limit; int core_temp_limit; /* degrees C */ int mch_temp_limit;}; /* Max temps are -10 degrees C to avoid PROCHOT# */ static struct ips_mcp_limits ips_sv_limits = { .mcp_power_limit = 35000, .core_power_limit = 29000, .mch_power_limit = 20000, .core_temp_limit = 95, .mch_temp_limit = 90}; static struct ips_mcp_limits ips_lv_limits = { .mcp_power_limit = 25000, .core_power_limit = 21000, .mch_power_limit = 13000, .core_temp_limit = 95, .mch_temp_limit = 90}; static struct ips_mcp_limits ips_ulv_limits = { .mcp_power_limit = 18000, .core_power_limit = 14000, .mch_power_limit = 11000, .core_temp_limit = 95, .mch_temp_limit = 90}; struct ips_driver { struct device *dev; void __iomem *regmap; int irq; struct task_struct *monitor; struct task_struct *adjust; struct dentry *debug_root; struct timer_list timer; /* Average CPU core temps (all averages in .01 degrees C for precision) */ u16 ctv1_avg_temp; u16 ctv2_avg_temp; /* GMCH average */ u16 mch_avg_temp; /* Average for the CPU (both cores?) */ u16 mcp_avg_temp; /* Average power consumption (in mW) */ u32 cpu_avg_power; u32 mch_avg_power; /* Offset values */ u16 cta_val; u16 pta_val; u16 mgta_val; /* Maximums & prefs, protected by turbo status lock */ spinlock_t turbo_status_lock; u16 mcp_temp_limit; u16 mcp_power_limit; u16 core_power_limit; u16 mch_power_limit; bool cpu_turbo_enabled; bool __cpu_turbo_on; bool gpu_turbo_enabled; bool __gpu_turbo_on; bool gpu_preferred; bool poll_turbo_status; bool second_cpu; bool turbo_toggle_allowed; struct ips_mcp_limits *limits; /* Optional MCH interfaces for if i915 is in use */ unsigned long (*read_mch_val)(void); bool (*gpu_raise)(void); bool (*gpu_lower)(void); bool (*gpu_busy)(void); bool (*gpu_turbo_disable)(void); /* For restoration at unload */ u64 orig_turbo_limit; u64 orig_turbo_ratios;}; static boolips_gpu_turbo_enabled(struct ips_driver *ips); /** * ips_cpu_busy - is CPU busy? * @ips: IPS driver struct * * Check CPU for load to see whether we should increase its thermal budget. * * RETURNS: * True if the CPU could use more power, false otherwise. */static bool ips_cpu_busy(struct ips_driver *ips){ if ((avenrun[0] >> FSHIFT) > 1) return true; return false;} /** * ips_cpu_raise - raise CPU power clamp * @ips: IPS driver struct * * Raise the CPU power clamp by %IPS_CPU_STEP, in accordance with TDP for * this platform. * * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR upwards (as * long as we haven't hit the TDP limit for the SKU). */static void ips_cpu_raise(struct ips_driver *ips){ u64 turbo_override; u16 cur_tdp_limit, new_tdp_limit; if (!ips->cpu_turbo_enabled) return; rdmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); cur_tdp_limit = turbo_override & TURBO_TDP_MASK; new_tdp_limit = cur_tdp_limit + 8; /* 1W increase */ /* Clamp to SKU TDP limit */ if (((new_tdp_limit * 10) / 8) > ips->core_power_limit) new_tdp_limit = cur_tdp_limit; thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8); turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; turbo_override |= new_tdp_limit; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override);} /** * ips_cpu_lower - lower CPU power clamp * @ips: IPS driver struct * * Lower CPU power clamp b %IPS_CPU_STEP if possible. * * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR down, going * as low as the platform limits will allow (though we could go lower there * wouldn't be much point). */static void ips_cpu_lower(struct ips_driver *ips){ u64 turbo_override; u16 cur_limit, new_limit; rdmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); cur_limit = turbo_override & TURBO_TDP_MASK; new_limit = cur_limit - 8; /* 1W decrease */ /* Clamp to SKU TDP limit */ if (new_limit < (ips->orig_turbo_limit & TURBO_TDP_MASK)) new_limit = ips->orig_turbo_limit & TURBO_TDP_MASK; thm_writew(THM_MPCPC, (new_limit * 10) / 8); turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; turbo_override |= new_limit; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override);} /** * do_enable_cpu_turbo - internal turbo enable function * @data: unused * * Internal function for actually updating MSRs. When we enable/disable * turbo, we need to do it on each CPU; this function is the one called * by on_each_cpu() when needed. */static void do_enable_cpu_turbo(void *data){ u64 perf_ctl; rdmsrq(IA32_PERF_CTL, perf_ctl); if (perf_ctl & IA32_PERF_TURBO_DIS) { perf_ctl &= ~IA32_PERF_TURBO_DIS; wrmsrq(IA32_PERF_CTL, perf_ctl); }} /** * ips_enable_cpu_turbo - enable turbo mode on all CPUs * @ips: IPS driver struct * * Enable turbo mode by clearing the disable bit in IA32_PERF_CTL on * all logical threads. */static void ips_enable_cpu_turbo(struct ips_driver *ips){ /* Already on, no need to mess with MSRs */ if (ips->__cpu_turbo_on) return; if (ips->turbo_toggle_allowed) on_each_cpu(do_enable_cpu_turbo, ips, 1); ips->__cpu_turbo_on = true;} /** * do_disable_cpu_turbo - internal turbo disable function * @data: unused * * Internal function for actually updating MSRs. When we enable/disable * turbo, we need to do it on each CPU; this function is the one called * by on_each_cpu() when needed. */static void do_disable_cpu_turbo(void *data){ u64 perf_ctl; rdmsrq(IA32_PERF_CTL, perf_ctl); if (!(perf_ctl & IA32_PERF_TURBO_DIS)) { perf_ctl |= IA32_PERF_TURBO_DIS; wrmsrq(IA32_PERF_CTL, perf_ctl); }} /** * ips_disable_cpu_turbo - disable turbo mode on all CPUs * @ips: IPS driver struct * * Disable turbo mode by setting the disable bit in IA32_PERF_CTL on * all logical threads. */static void ips_disable_cpu_turbo(struct ips_driver *ips){ /* Already off, leave it */ if (!ips->__cpu_turbo_on) return; if (ips->turbo_toggle_allowed) on_each_cpu(do_disable_cpu_turbo, ips, 1); Lines 1–500 of 1624. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2009-2010 Intel Corporation * * Authors: * Jesse Barnes <jbarnes@virtuousgeek.org> */ /* * Some Intel Ibex Peak based platforms support so-called "intelligent * power sharing", which allows the CPU and GPU to cooperate to maximize * performance within a given TDP (thermal design point). This driver * performs the coordination between the CPU and GPU, monitors thermal and * power statistics in the platform, and initializes power monitoring * hardware. It also provides a few tunables to control behavior. Its * primary purpose is to safely allow CPU and GPU turbo modes to be enabled * by tracking power and thermal budget; secondarily it can boost turbo * performance by allocating more power or thermal budget to the CPU or GPU * based on available headroom and activity. * * The basic algorithm is driven by a 5s moving average of temperature. If * thermal headroom is available, the CPU and/or GPU power clamps may be * adjusted upwards. If we hit the thermal ceiling or a thermal trigger, * we scale back the clamp. Aside from trigger events (when we're critically * close or over our TDP) we don't adjust the clamps more than once every * five seconds. * * The thermal device (device 31, function 6) has a set of registers that * are updated by the ME firmware. The ME should also take the clamp values * written to those registers and write them to the CPU, but we currently * bypass that functionality and write the CPU MSR directly. * * UNSUPPORTED: * - dual MCP configs * * TODO: * - handle CPU hotplug * - provide turbo enable/disable api * * Related documents: * - CDI 403777, 403778 - Auburndale EDS vol 1 & 2 * - CDI 401376 - Ibex Peak EDS * - ref 26037, 26641 - IPS BIOS spec * - ref 26489 - Nehalem BIOS writer's guide * - ref 26921 - Ibex Peak BIOS Specification */ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/sched.h> #include <linux/sched/loadavg.h> #include <linux/seq_file.h> #include <linux/string.h> #include <linux/tick.h> #include <linux/timer.h> #include <linux/dmi.h> #include <drm/intel/i915_drm.h> #include <asm/msr.h> #include <asm/processor.h> #include <asm/cpu_device_id.h> #include "intel_ips.h" #include <linux/io-64-nonatomic-lo-hi.h> #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32 /* * Package level MSRs for monitor/control */ #define PLATFORM_INFO 0xce #define PLATFORM_TDP (1<<29) #define PLATFORM_RATIO (1<<28) #define IA32_MISC_ENABLE 0x1a0 #define IA32_MISC_TURBO_EN (1ULL<<38) #define TURBO_POWER_CURRENT_LIMIT 0x1ac #define TURBO_TDC_OVR_EN (1UL<<31) #define TURBO_TDC_MASK (0x000000007fff0000UL) #define TURBO_TDC_SHIFT (16) #define TURBO_TDP_OVR_EN (1UL<<15) #define TURBO_TDP_MASK (0x0000000000003fffUL) /* * Core/thread MSRs for monitoring */ #define IA32_PERF_CTL 0x199 #define IA32_PERF_TURBO_DIS (1ULL<<32) /* * Thermal PCI device regs */ #define THM_CFG_TBAR 0x10 #define THM_CFG_TBAR_HI 0x14 #define THM_TSIU 0x00 #define THM_TSE 0x01 #define TSE_EN 0xb8 #define THM_TSS 0x02 #define THM_TSTR 0x03 #define THM_TSTTP 0x04 #define THM_TSCO 0x08 #define THM_TSES 0x0c #define THM_TSGPEN 0x0d #define TSGPEN_HOT_LOHI (1<<1) #define TSGPEN_CRIT_LOHI (1<<2) #define THM_TSPC 0x0e #define THM_PPEC 0x10 #define THM_CTA 0x12 #define THM_PTA 0x14 #define PTA_SLOPE_MASK (0xff00) #define PTA_SLOPE_SHIFT 8 #define PTA_OFFSET_MASK (0x00ff) #define THM_MGTA 0x16 #define MGTA_SLOPE_MASK (0xff00) #define MGTA_SLOPE_SHIFT 8 #define MGTA_OFFSET_MASK (0x00ff) #define THM_TRC 0x1a #define TRC_CORE2_EN (1<<15) #define TRC_THM_EN (1<<12) #define TRC_C6_WAR (1<<8) #define TRC_CORE1_EN (1<<7) #define TRC_CORE_PWR (1<<6) #define TRC_PCH_EN (1<<5) #define TRC_MCH_EN (1<<4) #define TRC_DIMM4 (1<<3) #define TRC_DIMM3 (1<<2) #define TRC_DIMM2 (1<<1) #define TRC_DIMM1 (1<<0) #define THM_TES 0x20 #define THM_TEN 0x21 #define TEN_UPDATE_EN 1 #define THM_PSC 0x24 #define PSC_NTG (1<<0) /* No GFX turbo support */ #define PSC_NTPC (1<<1) /* No CPU turbo support */ #define PSC_PP_DEF (0<<2) /* Perf policy up to driver */ #define PSP_PP_PC (1<<2) /* BIOS prefers CPU perf */ #define PSP_PP_BAL (2<<2) /* BIOS wants balanced perf */ #define PSP_PP_GFX (3<<2) /* BIOS prefers GFX perf */ #define PSP_PBRT (1<<4) /* BIOS run time support */ #define THM_CTV1 0x30 #define CTV_TEMP_ERROR (1<<15) #define CTV_TEMP_MASK 0x3f #define CTV_ #define THM_CTV2 0x32 #define THM_CEC 0x34 /* undocumented power accumulator in joules */ #define THM_AE 0x3f #define THM_HTS 0x50 /* 32 bits */ #define HTS_PCPL_MASK (0x7fe00000) #define HTS_PCPL_SHIFT 21 #define HTS_GPL_MASK (0x001ff000) #define HTS_GPL_SHIFT 12 #define HTS_PP_MASK (0x00000c00) #define HTS_PP_SHIFT 10 #define HTS_PP_DEF 0 #define HTS_PP_PROC 1 #define HTS_PP_BAL 2 #define HTS_PP_GFX 3 #define HTS_PCTD_DIS (1<<9) #define HTS_GTD_DIS (1<<8) #define HTS_PTL_MASK (0x000000fe) #define HTS_PTL_SHIFT 1 #define HTS_NVV (1<<0) #define THM_HTSHI 0x54 /* 16 bits */ #define HTS2_PPL_MASK (0x03ff) #define HTS2_PRST_MASK (0x3c00) #define HTS2_PRST_SHIFT 10 #define HTS2_PRST_UNLOADED 0 #define HTS2_PRST_RUNNING 1 #define HTS2_PRST_TDISOP 2 /* turbo disabled due to power */ #define HTS2_PRST_TDISHT 3 /* turbo disabled due to high temp */ #define HTS2_PRST_TDISUSR 4 /* user disabled turbo */ #define HTS2_PRST_TDISPLAT 5 /* platform disabled turbo */ #define HTS2_PRST_TDISPM 6 /* power management disabled turbo */ #define HTS2_PRST_TDISERR 7 /* some kind of error disabled turbo */ #define THM_PTL 0x56 #define THM_MGTV 0x58 #define TV_MASK 0x000000000000ff00 #define TV_SHIFT 8 #define THM_PTV 0x60 #define PTV_MASK 0x00ff #define THM_MMGPC 0x64 #define THM_MPPC 0x66 #define THM_MPCPC 0x68 #define THM_TSPIEN 0x82 #define TSPIEN_AUX_LOHI (1<<0) #define TSPIEN_HOT_LOHI (1<<1) #define TSPIEN_CRIT_LOHI (1<<2) #define TSPIEN_AUX2_LOHI (1<<3) #define THM_TSLOCK 0x83 #define THM_ATR 0x84 #define THM_TOF 0x87 #define THM_STS 0x98 #define STS_PCPL_MASK (0x7fe00000) #define STS_PCPL_SHIFT 21 #define STS_GPL_MASK (0x001ff000) #define STS_GPL_SHIFT 12 #define STS_PP_MASK (0x00000c00) #define STS_PP_SHIFT 10 #define STS_PP_DEF 0 #define STS_PP_PROC 1 #define STS_PP_BAL 2 #define STS_PP_GFX 3 #define STS_PCTD_DIS (1<<9) #define STS_GTD_DIS (1<<8) #define STS_PTL_MASK (0x000000fe) #define STS_PTL_SHIFT 1 #define STS_NVV (1<<0) #define THM_SEC 0x9c #define SEC_ACK (1<<0) #define THM_TC3 0xa4 #define THM_TC1 0xa8 #define STS_PPL_MASK (0x0003ff00) #define STS_PPL_SHIFT 16 #define THM_TC2 0xac #define THM_DTV 0xb0 #define THM_ITV 0xd8 #define ITV_ME_SEQNO_MASK 0x00ff0000 /* ME should update every ~200ms */ #define ITV_ME_SEQNO_SHIFT (16) #define ITV_MCH_TEMP_MASK 0x0000ff00 #define ITV_MCH_TEMP_SHIFT (8) #define ITV_PCH_TEMP_MASK 0x000000ff #define thm_readb(off) readb(ips->regmap + (off)) #define thm_readw(off) readw(ips->regmap + (off)) #define thm_readl(off) readl(ips->regmap + (off)) #define thm_readq(off) readq(ips->regmap + (off)) #define thm_writeb(off, val) writeb((val), ips->regmap + (off)) #define thm_writew(off, val) writew((val), ips->regmap + (off)) #define thm_writel(off, val) writel((val), ips->regmap + (off)) static const int IPS_ADJUST_PERIOD = 5000; /* ms */ static bool late_i915_load = false; /* For initial average collection */ static const int IPS_SAMPLE_PERIOD = 200; /* ms */ static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */ #define IPS_SAMPLE_COUNT (IPS_SAMPLE_WINDOW / IPS_SAMPLE_PERIOD) /* Per-SKU limits */ struct ips_mcp_limits { int mcp_power_limit; /* mW units */ int core_power_limit; int mch_power_limit; int core_temp_limit; /* degrees C */ int mch_temp_limit; }; /* Max temps are -10 degrees C to avoid PROCHOT# */ static struct ips_mcp_limits ips_sv_limits = { .mcp_power_limit = 35000, .core_power_limit = 29000, .mch_power_limit = 20000, .core_temp_limit = 95, .mch_temp_limit = 90 }; static struct ips_mcp_limits ips_lv_limits = { .mcp_power_limit = 25000, .core_power_limit = 21000, .mch_power_limit = 13000, .core_temp_limit = 95, .mch_temp_limit = 90 }; static struct ips_mcp_limits ips_ulv_limits = { .mcp_power_limit = 18000, .core_power_limit = 14000, .mch_power_limit = 11000, .core_temp_limit = 95, .mch_temp_limit = 90 }; struct ips_driver { struct device *dev; void __iomem *regmap; int irq; struct task_struct *monitor; struct task_struct *adjust; struct dentry *debug_root; struct timer_list timer; /* Average CPU core temps (all averages in .01 degrees C for precision) */ u16 ctv1_avg_temp; u16 ctv2_avg_temp; /* GMCH average */ u16 mch_avg_temp; /* Average for the CPU (both cores?) */ u16 mcp_avg_temp; /* Average power consumption (in mW) */ u32 cpu_avg_power; u32 mch_avg_power; /* Offset values */ u16 cta_val; u16 pta_val; u16 mgta_val; /* Maximums & prefs, protected by turbo status lock */ spinlock_t turbo_status_lock; u16 mcp_temp_limit; u16 mcp_power_limit; u16 core_power_limit; u16 mch_power_limit; bool cpu_turbo_enabled; bool __cpu_turbo_on; bool gpu_turbo_enabled; bool __gpu_turbo_on; bool gpu_preferred; bool poll_turbo_status; bool second_cpu; bool turbo_toggle_allowed; struct ips_mcp_limits *limits; /* Optional MCH interfaces for if i915 is in use */ unsigned long (*read_mch_val)(void); bool (*gpu_raise)(void); bool (*gpu_lower)(void); bool (*gpu_busy)(void); bool (*gpu_turbo_disable)(void); /* For restoration at unload */ u64 orig_turbo_limit; u64 orig_turbo_ratios; }; static bool ips_gpu_turbo_enabled(struct ips_driver *ips); /** * ips_cpu_busy - is CPU busy? * @ips: IPS driver struct * * Check CPU for load to see whether we should increase its thermal budget. * * RETURNS: * True if the CPU could use more power, false otherwise. */ static bool ips_cpu_busy(struct ips_driver *ips) { if ((avenrun[0] >> FSHIFT) > 1) return true; return false; } /** * ips_cpu_raise - raise CPU power clamp * @ips: IPS driver struct * * Raise the CPU power clamp by %IPS_CPU_STEP, in accordance with TDP for * this platform. * * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR upwards (as * long as we haven't hit the TDP limit for the SKU). */ static void ips_cpu_raise(struct ips_driver *ips) { u64 turbo_override; u16 cur_tdp_limit, new_tdp_limit; if (!ips->cpu_turbo_enabled) return; rdmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); cur_tdp_limit = turbo_override & TURBO_TDP_MASK; new_tdp_limit = cur_tdp_limit + 8; /* 1W increase */ /* Clamp to SKU TDP limit */ if (((new_tdp_limit * 10) / 8) > ips->core_power_limit) new_tdp_limit = cur_tdp_limit; thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8); turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; turbo_override |= new_tdp_limit; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); } /** * ips_cpu_lower - lower CPU power clamp * @ips: IPS driver struct * * Lower CPU power clamp b %IPS_CPU_STEP if possible. * * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR down, going * as low as the platform limits will allow (though we could go lower there * wouldn't be much point). */ static void ips_cpu_lower(struct ips_driver *ips) { u64 turbo_override; u16 cur_limit, new_limit; rdmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); cur_limit = turbo_override & TURBO_TDP_MASK; new_limit = cur_limit - 8; /* 1W decrease */ /* Clamp to SKU TDP limit */ if (new_limit < (ips->orig_turbo_limit & TURBO_TDP_MASK)) new_limit = ips->orig_turbo_limit & TURBO_TDP_MASK; thm_writew(THM_MPCPC, (new_limit * 10) / 8); turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; turbo_override |= new_limit; wrmsrq(TURBO_POWER_CURRENT_LIMIT, turbo_override); } /** * do_enable_cpu_turbo - internal turbo enable function * @data: unused * * Internal function for actually updating MSRs. When we enable/disable * turbo, we need to do it on each CPU; this function is the one called * by on_each_cpu() when needed. */ static void do_enable_cpu_turbo(void *data) { u64 perf_ctl; rdmsrq(IA32_PERF_CTL, perf_ctl); if (perf_ctl & IA32_PERF_TURBO_DIS) { perf_ctl &= ~IA32_PERF_TURBO_DIS; wrmsrq(IA32_PERF_CTL, perf_ctl); } } /** * ips_enable_cpu_turbo - enable turbo mode on all CPUs * @ips: IPS driver struct * * Enable turbo mode by clearing the disable bit in IA32_PERF_CTL on * all logical threads. */ static void ips_enable_cpu_turbo(struct ips_driver *ips) { /* Already on, no need to mess with MSRs */ if (ips->__cpu_turbo_on) return; if (ips->turbo_toggle_allowed) on_each_cpu(do_enable_cpu_turbo, ips, 1); ips->__cpu_turbo_on = true; } /** * do_disable_cpu_turbo - internal turbo disable function * @data: unused * * Internal function for actually updating MSRs. When we enable/disable * turbo, we need to do it on each CPU; this function is the one called * by on_each_cpu() when needed. */ static void do_disable_cpu_turbo(void *data) { u64 perf_ctl; rdmsrq(IA32_PERF_CTL, perf_ctl); if (!(perf_ctl & IA32_PERF_TURBO_DIS)) { perf_ctl |= IA32_PERF_TURBO_DIS; wrmsrq(IA32_PERF_CTL, perf_ctl); } } /** * ips_disable_cpu_turbo - disable turbo mode on all CPUs * @ips: IPS driver struct * * Disable turbo mode by setting the disable bit in IA32_PERF_CTL on * all logical threads. */ static void ips_disable_cpu_turbo(struct ips_driver *ips) { /* Already off, leave it */ if (!ips->__cpu_turbo_on) return; if (ips->turbo_toggle_allowed) on_each_cpu(do_disable_cpu_turbo, ips, 1);