Commit 50c6dc9e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of...

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86:
  IPS driver: Fix limit clamping when reducing CPU power
  [PATCH 2/2] IPS driver: disable CPU turbo
  IPS driver: apply BIOS provided CPU limit if different from default
  intel_ips -- ensure we do not enable gpu turbo mode without driver linkage
  intel_ips: Print MCP limit exceeded values.
  IPS driver: verify BIOS provided limits
  IPS driver: don't toggle CPU turbo on unsupported CPUs
  NULL pointer might be used in ips_monitor()
  Release symbol on error-handling path of ips_get_i915_syms()
  old_cpu_power is wrongly divided by 65535 in ips_monitor()
  seqno mask of THM_ITV register is 16bit
parents 6af0b78c d24a9da5
...@@ -51,7 +51,6 @@ ...@@ -51,7 +51,6 @@
* TODO: * TODO:
* - handle CPU hotplug * - handle CPU hotplug
* - provide turbo enable/disable api * - provide turbo enable/disable api
* - make sure we can write turbo enable/disable reg based on MISC_EN
* *
* Related documents: * Related documents:
* - CDI 403777, 403778 - Auburndale EDS vol 1 & 2 * - CDI 403777, 403778 - Auburndale EDS vol 1 & 2
...@@ -230,7 +229,7 @@ ...@@ -230,7 +229,7 @@
#define THM_TC2 0xac #define THM_TC2 0xac
#define THM_DTV 0xb0 #define THM_DTV 0xb0
#define THM_ITV 0xd8 #define THM_ITV 0xd8
#define ITV_ME_SEQNO_MASK 0x000f0000 /* ME should update every ~200ms */ #define ITV_ME_SEQNO_MASK 0x00ff0000 /* ME should update every ~200ms */
#define ITV_ME_SEQNO_SHIFT (16) #define ITV_ME_SEQNO_SHIFT (16)
#define ITV_MCH_TEMP_MASK 0x0000ff00 #define ITV_MCH_TEMP_MASK 0x0000ff00
#define ITV_MCH_TEMP_SHIFT (8) #define ITV_MCH_TEMP_SHIFT (8)
...@@ -325,6 +324,7 @@ struct ips_driver { ...@@ -325,6 +324,7 @@ struct ips_driver {
bool gpu_preferred; bool gpu_preferred;
bool poll_turbo_status; bool poll_turbo_status;
bool second_cpu; bool second_cpu;
bool turbo_toggle_allowed;
struct ips_mcp_limits *limits; struct ips_mcp_limits *limits;
/* Optional MCH interfaces for if i915 is in use */ /* Optional MCH interfaces for if i915 is in use */
...@@ -415,7 +415,7 @@ static void ips_cpu_lower(struct ips_driver *ips) ...@@ -415,7 +415,7 @@ static void ips_cpu_lower(struct ips_driver *ips)
new_limit = cur_limit - 8; /* 1W decrease */ new_limit = cur_limit - 8; /* 1W decrease */
/* Clamp to SKU TDP limit */ /* Clamp to SKU TDP limit */
if (((new_limit * 10) / 8) < (ips->orig_turbo_limit & TURBO_TDP_MASK)) if (new_limit < (ips->orig_turbo_limit & TURBO_TDP_MASK))
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); thm_writew(THM_MPCPC, (new_limit * 10) / 8);
...@@ -461,6 +461,7 @@ static void ips_enable_cpu_turbo(struct ips_driver *ips) ...@@ -461,6 +461,7 @@ static void ips_enable_cpu_turbo(struct ips_driver *ips)
if (ips->__cpu_turbo_on) if (ips->__cpu_turbo_on)
return; return;
if (ips->turbo_toggle_allowed)
on_each_cpu(do_enable_cpu_turbo, ips, 1); on_each_cpu(do_enable_cpu_turbo, ips, 1);
ips->__cpu_turbo_on = true; ips->__cpu_turbo_on = true;
...@@ -498,6 +499,7 @@ static void ips_disable_cpu_turbo(struct ips_driver *ips) ...@@ -498,6 +499,7 @@ static void ips_disable_cpu_turbo(struct ips_driver *ips)
if (!ips->__cpu_turbo_on) if (!ips->__cpu_turbo_on)
return; return;
if (ips->turbo_toggle_allowed)
on_each_cpu(do_disable_cpu_turbo, ips, 1); on_each_cpu(do_disable_cpu_turbo, ips, 1);
ips->__cpu_turbo_on = false; ips->__cpu_turbo_on = false;
...@@ -598,17 +600,29 @@ static bool mcp_exceeded(struct ips_driver *ips) ...@@ -598,17 +600,29 @@ static bool mcp_exceeded(struct ips_driver *ips)
{ {
unsigned long flags; unsigned long flags;
bool ret = false; bool ret = false;
u32 temp_limit;
u32 avg_power;
const char *msg = "MCP limit exceeded: ";
spin_lock_irqsave(&ips->turbo_status_lock, flags); spin_lock_irqsave(&ips->turbo_status_lock, flags);
if (ips->mcp_avg_temp > (ips->mcp_temp_limit * 100))
ret = true; temp_limit = ips->mcp_temp_limit * 100;
if (ips->cpu_avg_power + ips->mch_avg_power > ips->mcp_power_limit) if (ips->mcp_avg_temp > temp_limit) {
dev_info(&ips->dev->dev,
"%sAvg temp %u, limit %u\n", msg, ips->mcp_avg_temp,
temp_limit);
ret = true; ret = true;
spin_unlock_irqrestore(&ips->turbo_status_lock, flags); }
if (ret) avg_power = ips->cpu_avg_power + ips->mch_avg_power;
if (avg_power > ips->mcp_power_limit) {
dev_info(&ips->dev->dev, dev_info(&ips->dev->dev,
"MCP power or thermal limit exceeded\n"); "%sAvg power %u, limit %u\n", msg, avg_power,
ips->mcp_power_limit);
ret = true;
}
spin_unlock_irqrestore(&ips->turbo_status_lock, flags);
return ret; return ret;
} }
...@@ -662,6 +676,27 @@ static bool mch_exceeded(struct ips_driver *ips) ...@@ -662,6 +676,27 @@ static bool mch_exceeded(struct ips_driver *ips)
return ret; return ret;
} }
/**
* verify_limits - verify BIOS provided limits
* @ips: IPS structure
*
* BIOS can optionally provide non-default limits for power and temp. Check
* them here and use the defaults if the BIOS values are not provided or
* are otherwise unusable.
*/
static void verify_limits(struct ips_driver *ips)
{
if (ips->mcp_power_limit < ips->limits->mcp_power_limit ||
ips->mcp_power_limit > 35000)
ips->mcp_power_limit = ips->limits->mcp_power_limit;
if (ips->mcp_temp_limit < ips->limits->core_temp_limit ||
ips->mcp_temp_limit < ips->limits->mch_temp_limit ||
ips->mcp_temp_limit > 150)
ips->mcp_temp_limit = min(ips->limits->core_temp_limit,
ips->limits->mch_temp_limit);
}
/** /**
* update_turbo_limits - get various limits & settings from regs * update_turbo_limits - get various limits & settings from regs
* @ips: IPS driver struct * @ips: IPS driver struct
...@@ -680,12 +715,21 @@ static void update_turbo_limits(struct ips_driver *ips) ...@@ -680,12 +715,21 @@ static void update_turbo_limits(struct ips_driver *ips)
u32 hts = thm_readl(THM_HTS); u32 hts = thm_readl(THM_HTS);
ips->cpu_turbo_enabled = !(hts & HTS_PCTD_DIS); ips->cpu_turbo_enabled = !(hts & HTS_PCTD_DIS);
/*
* Disable turbo for now, until we can figure out why the power figures
* are wrong
*/
ips->cpu_turbo_enabled = false;
if (ips->gpu_busy)
ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS); ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS);
ips->core_power_limit = thm_readw(THM_MPCPC); ips->core_power_limit = thm_readw(THM_MPCPC);
ips->mch_power_limit = thm_readw(THM_MMGPC); ips->mch_power_limit = thm_readw(THM_MMGPC);
ips->mcp_temp_limit = thm_readw(THM_PTL); ips->mcp_temp_limit = thm_readw(THM_PTL);
ips->mcp_power_limit = thm_readw(THM_MPPC); ips->mcp_power_limit = thm_readw(THM_MPPC);
verify_limits(ips);
/* Ignore BIOS CPU vs GPU pref */ /* Ignore BIOS CPU vs GPU pref */
} }
...@@ -858,7 +902,7 @@ static u32 get_cpu_power(struct ips_driver *ips, u32 *last, int period) ...@@ -858,7 +902,7 @@ static u32 get_cpu_power(struct ips_driver *ips, u32 *last, int period)
ret = (ret * 1000) / 65535; ret = (ret * 1000) / 65535;
*last = val; *last = val;
return ret; return 0;
} }
static const u16 temp_decay_factor = 2; static const u16 temp_decay_factor = 2;
...@@ -940,7 +984,6 @@ static int ips_monitor(void *data) ...@@ -940,7 +984,6 @@ static int ips_monitor(void *data)
kfree(mch_samples); kfree(mch_samples);
kfree(cpu_samples); kfree(cpu_samples);
kfree(mchp_samples); kfree(mchp_samples);
kthread_stop(ips->adjust);
return -ENOMEM; return -ENOMEM;
} }
...@@ -948,7 +991,7 @@ static int ips_monitor(void *data) ...@@ -948,7 +991,7 @@ static int ips_monitor(void *data)
ITV_ME_SEQNO_SHIFT; ITV_ME_SEQNO_SHIFT;
seqno_timestamp = get_jiffies_64(); seqno_timestamp = get_jiffies_64();
old_cpu_power = thm_readl(THM_CEC) / 65535; old_cpu_power = thm_readl(THM_CEC);
schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD)); schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD));
/* Collect an initial average */ /* Collect an initial average */
...@@ -1150,11 +1193,18 @@ static irqreturn_t ips_irq_handler(int irq, void *arg) ...@@ -1150,11 +1193,18 @@ static irqreturn_t ips_irq_handler(int irq, void *arg)
STS_GPL_SHIFT; STS_GPL_SHIFT;
/* ignore EC CPU vs GPU pref */ /* ignore EC CPU vs GPU pref */
ips->cpu_turbo_enabled = !(sts & STS_PCTD_DIS); ips->cpu_turbo_enabled = !(sts & STS_PCTD_DIS);
/*
* Disable turbo for now, until we can figure
* out why the power figures are wrong
*/
ips->cpu_turbo_enabled = false;
if (ips->gpu_busy)
ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS); ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS);
ips->mcp_temp_limit = (sts & STS_PTL_MASK) >> ips->mcp_temp_limit = (sts & STS_PTL_MASK) >>
STS_PTL_SHIFT; STS_PTL_SHIFT;
ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >> ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >>
STS_PPL_SHIFT; STS_PPL_SHIFT;
verify_limits(ips);
spin_unlock(&ips->turbo_status_lock); spin_unlock(&ips->turbo_status_lock);
thm_writeb(THM_SEC, SEC_ACK); thm_writeb(THM_SEC, SEC_ACK);
...@@ -1333,8 +1383,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips) ...@@ -1333,8 +1383,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
* turbo manually or we'll get an illegal MSR access, even though * turbo manually or we'll get an illegal MSR access, even though
* turbo will still be available. * turbo will still be available.
*/ */
if (!(misc_en & IA32_MISC_TURBO_EN)) if (misc_en & IA32_MISC_TURBO_EN)
; /* add turbo MSR write allowed flag if necessary */ ips->turbo_toggle_allowed = true;
else
ips->turbo_toggle_allowed = false;
if (strstr(boot_cpu_data.x86_model_id, "CPU M")) if (strstr(boot_cpu_data.x86_model_id, "CPU M"))
limits = &ips_sv_limits; limits = &ips_sv_limits;
...@@ -1351,9 +1403,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips) ...@@ -1351,9 +1403,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
tdp = turbo_power & TURBO_TDP_MASK; tdp = turbo_power & TURBO_TDP_MASK;
/* Sanity check TDP against CPU */ /* Sanity check TDP against CPU */
if (limits->mcp_power_limit != (tdp / 8) * 1000) { if (limits->core_power_limit != (tdp / 8) * 1000) {
dev_warn(&ips->dev->dev, "Warning: CPU TDP doesn't match expected value (found %d, expected %d)\n", dev_info(&ips->dev->dev, "CPU TDP doesn't match expected value (found %d, expected %d)\n",
tdp / 8, limits->mcp_power_limit / 1000); tdp / 8, limits->core_power_limit / 1000);
limits->core_power_limit = (tdp / 8) * 1000;
} }
out: out:
...@@ -1390,7 +1443,7 @@ static bool ips_get_i915_syms(struct ips_driver *ips) ...@@ -1390,7 +1443,7 @@ static bool ips_get_i915_syms(struct ips_driver *ips)
return true; return true;
out_put_busy: out_put_busy:
symbol_put(i915_gpu_turbo_disable); symbol_put(i915_gpu_busy);
out_put_lower: out_put_lower:
symbol_put(i915_gpu_lower); symbol_put(i915_gpu_lower);
out_put_raise: out_put_raise:
...@@ -1532,22 +1585,27 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1532,22 +1585,27 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Save turbo limits & ratios */ /* Save turbo limits & ratios */
rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit); rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);
ips_enable_cpu_turbo(ips); ips_disable_cpu_turbo(ips);
ips->cpu_turbo_enabled = true; ips->cpu_turbo_enabled = false;
/* Set up the work queue and monitor/adjust threads */ /* Create thermal adjust thread */
ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor"); ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust");
if (IS_ERR(ips->monitor)) { if (IS_ERR(ips->adjust)) {
dev_err(&dev->dev, dev_err(&dev->dev,
"failed to create thermal monitor thread, aborting\n"); "failed to create thermal adjust thread, aborting\n");
ret = -ENOMEM; ret = -ENOMEM;
goto error_free_irq; goto error_free_irq;
} }
ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust"); /*
if (IS_ERR(ips->adjust)) { * Set up the work queue and monitor thread. The monitor thread
* will wake up ips_adjust thread.
*/
ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor");
if (IS_ERR(ips->monitor)) {
dev_err(&dev->dev, dev_err(&dev->dev,
"failed to create thermal adjust thread, aborting\n"); "failed to create thermal monitor thread, aborting\n");
ret = -ENOMEM; ret = -ENOMEM;
goto error_thread_cleanup; goto error_thread_cleanup;
} }
...@@ -1566,7 +1624,7 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1566,7 +1624,7 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
return ret; return ret;
error_thread_cleanup: error_thread_cleanup:
kthread_stop(ips->monitor); kthread_stop(ips->adjust);
error_free_irq: error_free_irq:
free_irq(ips->dev->irq, ips); free_irq(ips->dev->irq, ips);
error_unmap: error_unmap:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment