Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+90 −32
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@
 * TODO:
 *   - handle CPU hotplug
 *   - provide turbo enable/disable api
 *   - make sure we can write turbo enable/disable reg based on MISC_EN
 *
 * Related documents:
 *   - CDI 403777, 403778 - Auburndale EDS vol 1 & 2
@@ -230,7 +229,7 @@
#define THM_TC2		0xac
#define THM_DTV		0xb0
#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_MCH_TEMP_MASK 0x0000ff00
#define   ITV_MCH_TEMP_SHIFT (8)
@@ -325,6 +324,7 @@ struct ips_driver {
	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 */
@@ -415,7 +415,7 @@ static void ips_cpu_lower(struct ips_driver *ips)
	new_limit = cur_limit - 8; /* 1W decrease */

	/* 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;

	thm_writew(THM_MPCPC, (new_limit * 10) / 8);
@@ -461,6 +461,7 @@ static void ips_enable_cpu_turbo(struct ips_driver *ips)
	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;
@@ -498,6 +499,7 @@ static void ips_disable_cpu_turbo(struct ips_driver *ips)
	if (!ips->__cpu_turbo_on)
		return;

	if (ips->turbo_toggle_allowed)
		on_each_cpu(do_disable_cpu_turbo, ips, 1);

	ips->__cpu_turbo_on = false;
@@ -598,17 +600,29 @@ static bool mcp_exceeded(struct ips_driver *ips)
{
	unsigned long flags;
	bool ret = false;
	u32 temp_limit;
	u32 avg_power;
	const char *msg = "MCP limit exceeded: ";

	spin_lock_irqsave(&ips->turbo_status_lock, flags);
	if (ips->mcp_avg_temp > (ips->mcp_temp_limit * 100))
		ret = true;
	if (ips->cpu_avg_power + ips->mch_avg_power > ips->mcp_power_limit)

	temp_limit = ips->mcp_temp_limit * 100;
	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;
	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,
			 "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;
}
@@ -662,6 +676,27 @@ static bool mch_exceeded(struct ips_driver *ips)
	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
 * @ips: IPS driver struct
@@ -680,12 +715,21 @@ static void update_turbo_limits(struct ips_driver *ips)
	u32 hts = thm_readl(THM_HTS);

	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->core_power_limit = thm_readw(THM_MPCPC);
	ips->mch_power_limit = thm_readw(THM_MMGPC);
	ips->mcp_temp_limit = thm_readw(THM_PTL);
	ips->mcp_power_limit = thm_readw(THM_MPPC);

	verify_limits(ips);
	/* Ignore BIOS CPU vs GPU pref */
}

@@ -858,7 +902,7 @@ static u32 get_cpu_power(struct ips_driver *ips, u32 *last, int period)
	ret = (ret * 1000) / 65535;
	*last = val;

	return ret;
	return 0;
}

static const u16 temp_decay_factor = 2;
@@ -940,7 +984,6 @@ static int ips_monitor(void *data)
		kfree(mch_samples);
		kfree(cpu_samples);
		kfree(mchp_samples);
		kthread_stop(ips->adjust);
		return -ENOMEM;
	}

@@ -948,7 +991,7 @@ static int ips_monitor(void *data)
		ITV_ME_SEQNO_SHIFT;
	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));

	/* Collect an initial average */
@@ -1150,11 +1193,18 @@ static irqreturn_t ips_irq_handler(int irq, void *arg)
				STS_GPL_SHIFT;
			/* ignore EC CPU vs GPU pref */
			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->mcp_temp_limit = (sts & STS_PTL_MASK) >>
				STS_PTL_SHIFT;
			ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >>
				STS_PPL_SHIFT;
			verify_limits(ips);
			spin_unlock(&ips->turbo_status_lock);

			thm_writeb(THM_SEC, SEC_ACK);
@@ -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 will still be available.
	 */
	if (!(misc_en & IA32_MISC_TURBO_EN))
		; /* add turbo MSR write allowed flag if necessary */
	if (misc_en & IA32_MISC_TURBO_EN)
		ips->turbo_toggle_allowed = true;
	else
		ips->turbo_toggle_allowed = false;

	if (strstr(boot_cpu_data.x86_model_id, "CPU       M"))
		limits = &ips_sv_limits;
@@ -1351,9 +1403,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips)
	tdp = turbo_power & TURBO_TDP_MASK;

	/* Sanity check TDP against CPU */
	if (limits->mcp_power_limit != (tdp / 8) * 1000) {
		dev_warn(&ips->dev->dev, "Warning: CPU TDP doesn't match expected value (found %d, expected %d)\n",
			 tdp / 8, limits->mcp_power_limit / 1000);
	if (limits->core_power_limit != (tdp / 8) * 1000) {
		dev_info(&ips->dev->dev, "CPU TDP doesn't match expected value (found %d, expected %d)\n",
			 tdp / 8, limits->core_power_limit / 1000);
		limits->core_power_limit = (tdp / 8) * 1000;
	}

out:
@@ -1390,7 +1443,7 @@ static bool ips_get_i915_syms(struct ips_driver *ips)
	return true;

out_put_busy:
	symbol_put(i915_gpu_turbo_disable);
	symbol_put(i915_gpu_busy);
out_put_lower:
	symbol_put(i915_gpu_lower);
out_put_raise:
@@ -1532,22 +1585,27 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
	/* Save turbo limits & ratios */
	rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit);

	ips_enable_cpu_turbo(ips);
	ips->cpu_turbo_enabled = true;
	ips_disable_cpu_turbo(ips);
	ips->cpu_turbo_enabled = false;

	/* Set up the work queue and monitor/adjust threads */
	ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor");
	if (IS_ERR(ips->monitor)) {
	/* Create thermal adjust thread */
	ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust");
	if (IS_ERR(ips->adjust)) {
		dev_err(&dev->dev,
			"failed to create thermal monitor thread, aborting\n");
			"failed to create thermal adjust thread, aborting\n");
		ret = -ENOMEM;
		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,
			"failed to create thermal adjust thread, aborting\n");
			"failed to create thermal monitor thread, aborting\n");
		ret = -ENOMEM;
		goto error_thread_cleanup;
	}
@@ -1566,7 +1624,7 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
	return ret;

error_thread_cleanup:
	kthread_stop(ips->monitor);
	kthread_stop(ips->adjust);
error_free_irq:
	free_irq(ips->dev->irq, ips);
error_unmap: