1624 lines · 41.8 KB · C
RawDownload
// 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t