[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: Mattia Dongili <malattia@linux.it> Acked-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Dave 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(-)
This commit is contained in:
parent
fc457fa7c0
commit
1a10760c91
@ -315,10 +315,11 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||||||
cpus_allowed = current->cpus_allowed;
|
cpus_allowed = current->cpus_allowed;
|
||||||
set_cpus_allowed(current, policy->cpus);
|
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,
|
result = speedstep_get_freqs(speedstep_processor,
|
||||||
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
|
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
|
||||||
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
|
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
|
||||||
|
&policy->cpuinfo.transition_latency,
|
||||||
&speedstep_set_state);
|
&speedstep_set_state);
|
||||||
set_cpus_allowed(current, cpus_allowed);
|
set_cpus_allowed(current, cpus_allowed);
|
||||||
if (result)
|
if (result)
|
||||||
@ -335,7 +336,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||||||
|
|
||||||
/* cpuinfo and default policy values */
|
/* cpuinfo and default policy values */
|
||||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
|
||||||
policy->cur = speed;
|
policy->cur = speed;
|
||||||
|
|
||||||
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
|
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
|
||||||
|
@ -320,11 +320,13 @@ EXPORT_SYMBOL_GPL(speedstep_detect_processor);
|
|||||||
unsigned int speedstep_get_freqs(unsigned int processor,
|
unsigned int speedstep_get_freqs(unsigned int processor,
|
||||||
unsigned int *low_speed,
|
unsigned int *low_speed,
|
||||||
unsigned int *high_speed,
|
unsigned int *high_speed,
|
||||||
|
unsigned int *transition_latency,
|
||||||
void (*set_state) (unsigned int state))
|
void (*set_state) (unsigned int state))
|
||||||
{
|
{
|
||||||
unsigned int prev_speed;
|
unsigned int prev_speed;
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct timeval tv1, tv2;
|
||||||
|
|
||||||
if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
|
if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -337,7 +339,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
dprintk("previous speed is %u\n", prev_speed);
|
dprintk("previous speed is %u\n", prev_speed);
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
|
|
||||||
/* switch to low state */
|
/* switch to low state */
|
||||||
@ -350,8 +352,17 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||||||
|
|
||||||
dprintk("low speed is %u\n", *low_speed);
|
dprintk("low speed is %u\n", *low_speed);
|
||||||
|
|
||||||
|
/* start latency measurement */
|
||||||
|
if (transition_latency)
|
||||||
|
do_gettimeofday(&tv1);
|
||||||
|
|
||||||
/* switch to high state */
|
/* switch to high state */
|
||||||
set_state(SPEEDSTEP_HIGH);
|
set_state(SPEEDSTEP_HIGH);
|
||||||
|
|
||||||
|
/* end latency measurement */
|
||||||
|
if (transition_latency)
|
||||||
|
do_gettimeofday(&tv2);
|
||||||
|
|
||||||
*high_speed = speedstep_get_processor_frequency(processor);
|
*high_speed = speedstep_get_processor_frequency(processor);
|
||||||
if (!*high_speed) {
|
if (!*high_speed) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
@ -369,6 +380,25 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||||||
if (*high_speed != prev_speed)
|
if (*high_speed != prev_speed)
|
||||||
set_state(SPEEDSTEP_LOW);
|
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:
|
out:
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
return (ret);
|
return (ret);
|
||||||
|
@ -44,4 +44,5 @@ extern unsigned int speedstep_get_processor_frequency(unsigned int processor);
|
|||||||
extern unsigned int speedstep_get_freqs(unsigned int processor,
|
extern unsigned int speedstep_get_freqs(unsigned int processor,
|
||||||
unsigned int *low_speed,
|
unsigned int *low_speed,
|
||||||
unsigned int *high_speed,
|
unsigned int *high_speed,
|
||||||
|
unsigned int *transition_latency,
|
||||||
void (*set_state) (unsigned int state));
|
void (*set_state) (unsigned int state));
|
||||||
|
@ -269,6 +269,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||||||
result = speedstep_get_freqs(speedstep_processor,
|
result = speedstep_get_freqs(speedstep_processor,
|
||||||
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
|
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
|
||||||
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
|
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
|
||||||
|
NULL,
|
||||||
&speedstep_set_state);
|
&speedstep_set_state);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
Loading…
Reference in New Issue
Block a user