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

Commit 1a10760c authored by Mattia Dongili's avatar Mattia Dongili Committed by Dave Jones
Browse files

[CPUFREQ] Measure transition latency at driver initialization



The attached patch introduces runtime latency measurement for ICH[234]
based chipsets instead of using CPUFREQ_ETERNAL. It includes
some sanity checks in case the measured value is out of range and
assigns a safe value of 500uSec that should still be enough on
problematics chipsets (current testing report values ~200uSec). The
measurement is currently done in speedstep_get_freqs in order to avoid
further unnecessary transitions and in the hope it'll come handy for SMI
also.

Signed-off-by: default avatarMattia Dongili <malattia@linux.it>
Acked-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: default avatarDave Jones <davej@redhat.com>

 speedstep-ich.c |    4 ++--
 speedstep-lib.c |   32 +++++++++++++++++++++++++++++++-
 speedstep-lib.h |    1 +
 speedstep-smi.c |    1 +
 4 files changed, 35 insertions(+), 3 deletions(-)
parent fc457fa7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -315,10 +315,11 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
	cpus_allowed = current->cpus_allowed;
	set_cpus_allowed(current, policy->cpus);

	/* detect low and high frequency */
	/* detect low and high frequency and transition latency */
	result = speedstep_get_freqs(speedstep_processor,
				     &speedstep_freqs[SPEEDSTEP_LOW].frequency,
				     &speedstep_freqs[SPEEDSTEP_HIGH].frequency,
				     &policy->cpuinfo.transition_latency,
				     &speedstep_set_state);
	set_cpus_allowed(current, cpus_allowed);
	if (result)
@@ -335,7 +336,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)

	/* cpuinfo and default policy values */
	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
	policy->cur = speed;

	result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
+31 −1
Original line number Diff line number Diff line
@@ -320,11 +320,13 @@ EXPORT_SYMBOL_GPL(speedstep_detect_processor);
unsigned int speedstep_get_freqs(unsigned int processor,
				  unsigned int *low_speed,
				  unsigned int *high_speed,
				  unsigned int *transition_latency,
				  void (*set_state) (unsigned int state))
{
	unsigned int prev_speed;
	unsigned int ret = 0;
	unsigned long flags;
	struct timeval tv1, tv2;

	if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
		return -EINVAL;
@@ -350,8 +352,17 @@ unsigned int speedstep_get_freqs(unsigned int processor,

	dprintk("low speed is %u\n", *low_speed);

	/* start latency measurement */
	if (transition_latency)
		do_gettimeofday(&tv1);

	/* switch to high state */
	set_state(SPEEDSTEP_HIGH);

	/* end latency measurement */
	if (transition_latency)
		do_gettimeofday(&tv2);

	*high_speed = speedstep_get_processor_frequency(processor);
	if (!*high_speed) {
		ret = -EIO;
@@ -369,6 +380,25 @@ unsigned int speedstep_get_freqs(unsigned int processor,
	if (*high_speed != prev_speed)
		set_state(SPEEDSTEP_LOW);

	if (transition_latency) {
		*transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC +
			tv2.tv_usec - tv1.tv_usec;
		dprintk("transition latency is %u uSec\n", *transition_latency);

		/* convert uSec to nSec and add 20% for safety reasons */
		*transition_latency *= 1200;

		/* check if the latency measurement is too high or too low
		 * and set it to a safe value (500uSec) in that case
		 */
		if (*transition_latency > 10000000 || *transition_latency < 50000) {
			printk (KERN_WARNING "speedstep: frequency transition measured seems out of "
					"range (%u nSec), falling back to a safe one of %u nSec.\n",
					*transition_latency, 500000);
			*transition_latency = 500000;
		}
	}

 out:
	local_irq_restore(flags);
	return (ret);
+1 −0
Original line number Diff line number Diff line
@@ -44,4 +44,5 @@ extern unsigned int speedstep_get_processor_frequency(unsigned int processor);
extern unsigned int speedstep_get_freqs(unsigned int processor,
	  unsigned int *low_speed,
	  unsigned int *high_speed,
	  unsigned int *transition_latency,
	  void (*set_state) (unsigned int state));
+1 −0
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
		result = speedstep_get_freqs(speedstep_processor,
				&speedstep_freqs[SPEEDSTEP_LOW].frequency,
				&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
				NULL,
				&speedstep_set_state);

		if (result) {