Commit 1013687e authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Kai Germaschewski

[PATCH] cpufreq: frequency table helpers

This patch adds "frequency table helpers" to kernel/cpufreq.c and
updates some drivers to use them.

Most CPU frequency scaling methods only support a few static
frequencies. In these drivers a lot of duplicated code existed in the
->setpolicy and ->verify calls.

Please note that this in no way changes the behaviour of cpufreq or of
the ->setpolicy or ->verify calls. These "frequency table helpers"
aren't for drivers which either only support policies (longrun) or
really many frequency states (ARM, gx-suspmod).
parent c78874ac
...@@ -61,6 +61,18 @@ struct s_elan_multiplier elan_multiplier[] = { ...@@ -61,6 +61,18 @@ struct s_elan_multiplier elan_multiplier[] = {
{99000, 0x01, 0x05} {99000, 0x01, 0x05}
}; };
static struct cpufreq_frequency_table elanfreq_table[] = {
{0, 1000},
{1, 2000},
{2, 4000},
{3, 8000},
{4, 16000},
{5, 33000},
{6, 66000},
{7, 99000},
{0, CPUFREQ_TABLE_END},
};
/** /**
* elanfreq_get_cpu_frequency: determine current cpu speed * elanfreq_get_cpu_frequency: determine current cpu speed
...@@ -172,63 +184,17 @@ static void elanfreq_set_cpu_state (unsigned int state) { ...@@ -172,63 +184,17 @@ static void elanfreq_set_cpu_state (unsigned int state) {
static int elanfreq_verify (struct cpufreq_policy *policy) static int elanfreq_verify (struct cpufreq_policy *policy)
{ {
unsigned int number_states = 0; return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]);
unsigned int i;
if (!policy || !max_freq)
return -EINVAL;
policy->cpu = 0;
cpufreq_verify_within_limits(policy, 1000, max_freq);
for (i=7; i>=0; i--)
if ((elan_multiplier[i].clock >= policy->min) &&
(elan_multiplier[i].clock <= policy->max))
number_states++;
if (number_states)
return 0;
for (i=7; i>=0; i--)
if (elan_multiplier[i].clock < policy->max)
break;
policy->max = elan_multiplier[i+1].clock;
cpufreq_verify_within_limits(policy, 1000, max_freq);
return 0;
} }
static int elanfreq_setpolicy (struct cpufreq_policy *policy) static int elanfreq_setpolicy (struct cpufreq_policy *policy)
{ {
unsigned int i; unsigned int newstate = 0;
unsigned int optimal = 8;
if (!elanfreq_driver)
return -EINVAL;
for (i=0; i<8; i++) { if (cpufreq_frequency_table_setpolicy(policy, &elanfreq_table[0], &newstate))
if ((elan_multiplier[i].clock > policy->max) ||
(elan_multiplier[i].clock < policy->min))
continue;
switch(policy->policy) {
case CPUFREQ_POLICY_POWERSAVE:
if (optimal == 8)
optimal = i;
break;
case CPUFREQ_POLICY_PERFORMANCE:
optimal = i;
break;
default:
return -EINVAL;
}
}
if ((optimal == 8) || (elan_multiplier[optimal].clock > max_freq))
return -EINVAL; return -EINVAL;
elanfreq_set_cpu_state(optimal); elanfreq_set_cpu_state(newstate);
return 0; return 0;
} }
...@@ -262,7 +228,7 @@ static int __init elanfreq_init(void) ...@@ -262,7 +228,7 @@ static int __init elanfreq_init(void)
{ {
struct cpuinfo_x86 *c = cpu_data; struct cpuinfo_x86 *c = cpu_data;
struct cpufreq_driver *driver; struct cpufreq_driver *driver;
int ret; int ret, i;
/* Test if we have the right hardware */ /* Test if we have the right hardware */
if ((c->x86_vendor != X86_VENDOR_AMD) || if ((c->x86_vendor != X86_VENDOR_AMD) ||
...@@ -282,6 +248,12 @@ static int __init elanfreq_init(void) ...@@ -282,6 +248,12 @@ static int __init elanfreq_init(void)
if (!max_freq) if (!max_freq)
max_freq = elanfreq_get_cpu_frequency(); max_freq = elanfreq_get_cpu_frequency();
/* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = elanfreq_get_cpu_frequency(); driver->cpu_cur_freq[0] = elanfreq_get_cpu_frequency();
#endif #endif
...@@ -290,11 +262,12 @@ static int __init elanfreq_init(void) ...@@ -290,11 +262,12 @@ static int __init elanfreq_init(void)
driver->setpolicy = &elanfreq_setpolicy; driver->setpolicy = &elanfreq_setpolicy;
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
driver->policy[0].min = 1000; ret = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &elanfreq_table[0]);
driver->policy[0].max = max_freq; if (ret) {
kfree(driver);
return ret;
}
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE; driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.max_freq = max_freq;
driver->policy[0].cpuinfo.min_freq = 1000;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
elanfreq_driver = driver; elanfreq_driver = driver;
......
...@@ -141,39 +141,27 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) ...@@ -141,39 +141,27 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
} }
static struct cpufreq_frequency_table p4clockmod_table[] = {
{DC_RESV, CPUFREQ_ENTRY_INVALID},
{DC_DFLT, 0},
{DC_25PT, 0},
{DC_38PT, 0},
{DC_50PT, 0},
{DC_64PT, 0},
{DC_75PT, 0},
{DC_88PT, 0},
{DC_DISABLE, 0},
{DC_RESV, CPUFREQ_TABLE_END},
};
static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy) static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy)
{ {
unsigned int i; unsigned int newstate = DC_RESV;
unsigned int newstate = 0;
unsigned int number_states = 0;
unsigned int minstate = 1;
if (!cpufreq_p4_driver || !stock_freq || if (cpufreq_frequency_table_setpolicy(policy, &p4clockmod_table[0], &newstate))
!policy || !cpu_online(policy->cpu))
return -EINVAL; return -EINVAL;
if (has_N44_O17_errata)
minstate = 3;
if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
{
for (i=8; i>=minstate; i--)
if ((policy->min <= ((stock_freq / 8) * i)) &&
(policy->max >= ((stock_freq / 8) * i)))
{
newstate = i;
number_states++;
}
} else {
for (i=minstate; i<=8; i++)
if ((policy->min <= ((stock_freq / 8) * i)) &&
(policy->max >= ((stock_freq / 8) * i)))
{
newstate = i;
number_states++;
}
}
cpufreq_p4_setdc(policy->cpu, newstate); cpufreq_p4_setdc(policy->cpu, newstate);
return 0; return 0;
...@@ -182,34 +170,7 @@ static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy) ...@@ -182,34 +170,7 @@ static int cpufreq_p4_setpolicy(struct cpufreq_policy *policy)
static int cpufreq_p4_verify(struct cpufreq_policy *policy) static int cpufreq_p4_verify(struct cpufreq_policy *policy)
{ {
unsigned int number_states = 0; return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]);
unsigned int i = 1;
if (!cpufreq_p4_driver || !stock_freq ||
!policy || !cpu_online(policy->cpu))
return -EINVAL;
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
if (has_N44_O17_errata)
i = 3;
/* is there at least one state within the limit? */
for (; i<=8; i++)
if ((policy->min <= ((stock_freq / 8) * i)) &&
(policy->max >= ((stock_freq / 8) * i)))
number_states++;
if (number_states)
return 0;
policy->max = (stock_freq / 8) * (((unsigned int) ((policy->max * 8) / stock_freq)) + 1);
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
return 0;
} }
...@@ -262,6 +223,15 @@ static int __init cpufreq_p4_init(void) ...@@ -262,6 +223,15 @@ static int __init cpufreq_p4_init(void)
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
/* table init */
for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if ((i<2) && (has_N44_O17_errata))
p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
else
p4clockmod_table[i].frequency = (stock_freq * i)/8;
}
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
for (i=0;i<NR_CPUS;i++) { for (i=0;i<NR_CPUS;i++) {
driver->cpu_cur_freq[i] = stock_freq; driver->cpu_cur_freq[i] = stock_freq;
...@@ -272,17 +242,14 @@ static int __init cpufreq_p4_init(void) ...@@ -272,17 +242,14 @@ static int __init cpufreq_p4_init(void)
driver->setpolicy = &cpufreq_p4_setpolicy; driver->setpolicy = &cpufreq_p4_setpolicy;
for (i=0;i<NR_CPUS;i++) { for (i=0;i<NR_CPUS;i++) {
if (has_N44_O17_errata) driver->policy[i].cpu = i;
driver->policy[i].min = (stock_freq * 3) / 8; ret = cpufreq_frequency_table_cpuinfo(&driver->policy[i], &p4clockmod_table[0]);
else if (ret) {
driver->policy[i].min = stock_freq / 8; kfree(driver);
driver->policy[i].max = stock_freq; return ret;
}
driver->policy[i].policy = CPUFREQ_POLICY_PERFORMANCE; driver->policy[i].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[i].cpuinfo.min_freq = driver->policy[i].min;
driver->policy[i].cpuinfo.max_freq = stock_freq;
driver->policy[i].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[i].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->policy[i].cpu = i;
} }
cpufreq_p4_driver = driver; cpufreq_p4_driver = driver;
......
...@@ -31,15 +31,16 @@ static unsigned int max_multiplier; ...@@ -31,15 +31,16 @@ static unsigned int max_multiplier;
/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
static int clock_ratio[8] = { static struct cpufreq_frequency_table clock_ratio[] = {
45, /* 000 -> 4.5x */ {45, /* 000 -> 4.5x */ 0},
50, /* 001 -> 5.0x */ {50, /* 001 -> 5.0x */ 0},
40, /* 010 -> 4.0x */ {40, /* 010 -> 4.0x */ 0},
55, /* 011 -> 5.5x */ {55, /* 011 -> 5.5x */ 0},
20, /* 100 -> 2.0x */ {20, /* 100 -> 2.0x */ 0},
30, /* 101 -> 3.0x */ {30, /* 101 -> 3.0x */ 0},
60, /* 110 -> 6.0x */ {60, /* 110 -> 6.0x */ 0},
35 /* 111 -> 3.5x */ {35, /* 111 -> 3.5x */ 0},
{0, CPUFREQ_TABLE_END}
}; };
...@@ -60,7 +61,7 @@ static int powernow_k6_get_cpu_multiplier(void) ...@@ -60,7 +61,7 @@ static int powernow_k6_get_cpu_multiplier(void)
msrval = POWERNOW_IOPORT + 0x0; msrval = POWERNOW_IOPORT + 0x0;
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
return clock_ratio[(invalue >> 5)&7]; return clock_ratio[(invalue >> 5)&7].index;
} }
...@@ -82,7 +83,7 @@ static void powernow_k6_set_state (unsigned int best_i) ...@@ -82,7 +83,7 @@ static void powernow_k6_set_state (unsigned int best_i)
} }
freqs.old = busfreq * powernow_k6_get_cpu_multiplier(); freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
freqs.new = busfreq * clock_ratio[best_i]; freqs.new = busfreq * clock_ratio[best_i].index;
freqs.cpu = 0; /* powernow-k6.c is UP only driver */ freqs.cpu = 0; /* powernow-k6.c is UP only driver */
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
...@@ -115,39 +116,7 @@ static void powernow_k6_set_state (unsigned int best_i) ...@@ -115,39 +116,7 @@ static void powernow_k6_set_state (unsigned int best_i)
*/ */
static int powernow_k6_verify(struct cpufreq_policy *policy) static int powernow_k6_verify(struct cpufreq_policy *policy)
{ {
unsigned int number_states = 0; return cpufreq_frequency_table_verify(policy, &clock_ratio[0]);
unsigned int i, j;
if (!policy || !busfreq)
return -EINVAL;
policy->cpu = 0;
cpufreq_verify_within_limits(policy, (20 * busfreq),
(max_multiplier * busfreq));
for (i=0; i<8; i++)
if ((policy->min <= (busfreq * clock_ratio[i])) &&
(policy->max >= (busfreq * clock_ratio[i])))
number_states++;
if (number_states)
return 0;
/* no state is available within range -- find next larger state */
j = 6;
for (i=0; i<8; i++)
if (((clock_ratio[i] * busfreq) >= policy->min) &&
(clock_ratio[i] < clock_ratio[j]))
j = i;
policy->max = clock_ratio[j] * busfreq;
cpufreq_verify_within_limits(policy, (20 * busfreq),
(max_multiplier * busfreq));
return 0;
} }
...@@ -159,43 +128,12 @@ static int powernow_k6_verify(struct cpufreq_policy *policy) ...@@ -159,43 +128,12 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
*/ */
static int powernow_k6_setpolicy (struct cpufreq_policy *policy) static int powernow_k6_setpolicy (struct cpufreq_policy *policy)
{ {
unsigned int i; unsigned int newstate = 0;
unsigned int optimal;
if (!powernow_driver || !policy || policy->cpu)
return -EINVAL;
switch(policy->policy) { if (cpufreq_frequency_table_setpolicy(policy, &clock_ratio[0], &newstate))
case CPUFREQ_POLICY_POWERSAVE:
optimal = 6;
break;
case CPUFREQ_POLICY_PERFORMANCE:
optimal = max_multiplier;
break;
default:
return -EINVAL; return -EINVAL;
}
for (i=0;i<8;i++) { powernow_k6_set_state(newstate);
unsigned int freq = busfreq * clock_ratio[i];
if (clock_ratio[i] > max_multiplier)
continue;
if ((freq > policy->max) ||
(freq < policy->min))
continue;
switch(policy->policy) {
case CPUFREQ_POLICY_POWERSAVE:
if (freq < (clock_ratio[optimal] * busfreq))
optimal = i;
break;
case CPUFREQ_POLICY_PERFORMANCE:
if (freq > (clock_ratio[optimal] * busfreq))
optimal = i;
break;
}
}
powernow_k6_set_state(optimal);
return 0; return 0;
} }
...@@ -213,6 +151,7 @@ static int __init powernow_k6_init(void) ...@@ -213,6 +151,7 @@ static int __init powernow_k6_init(void)
struct cpuinfo_x86 *c = cpu_data; struct cpuinfo_x86 *c = cpu_data;
struct cpufreq_driver *driver; struct cpufreq_driver *driver;
unsigned int result; unsigned int result;
unsigned int i;
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13))) ((c->x86_model != 12) && (c->x86_model != 13)))
...@@ -235,20 +174,29 @@ static int __init powernow_k6_init(void) ...@@ -235,20 +174,29 @@ static int __init powernow_k6_init(void)
} }
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
#ifdef CONFIG_CPU_FREQ_24_API /* table init */
driver->cpu_cur_freq[0] = busfreq * max_multiplier; for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
#endif if (clock_ratio[i].index > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
else
clock_ratio[i].frequency = busfreq * clock_ratio[i].index;
}
driver->verify = &powernow_k6_verify; driver->verify = &powernow_k6_verify;
driver->setpolicy = &powernow_k6_setpolicy; driver->setpolicy = &powernow_k6_setpolicy;
/* cpuinfo and default policy values */
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
driver->policy[0].min = busfreq * 20;
driver->policy[0].max = busfreq * max_multiplier;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.max_freq = busfreq * max_multiplier;
driver->policy[0].cpuinfo.min_freq = busfreq * 20;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = busfreq * max_multiplier;
#endif
result = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &clock_ratio[0]);
if (result) {
kfree(driver);
return result;
}
powernow_driver = driver; powernow_driver = driver;
...@@ -274,7 +222,7 @@ static void __exit powernow_k6_exit(void) ...@@ -274,7 +222,7 @@ static void __exit powernow_k6_exit(void)
if (powernow_driver) { if (powernow_driver) {
for (i=0;i<8;i++) for (i=0;i<8;i++)
if (clock_ratio[i] == max_multiplier) if (clock_ratio[i].index == max_multiplier)
powernow_k6_set_state(i); powernow_k6_set_state(i);
cpufreq_unregister(); cpufreq_unregister();
kfree(powernow_driver); kfree(powernow_driver);
......
...@@ -58,12 +58,18 @@ static int speedstep_coppermine = 0; ...@@ -58,12 +58,18 @@ static int speedstep_coppermine = 0;
* There are only two frequency states for each processor. Values * There are only two frequency states for each processor. Values
* are in kHz for the time being. * are in kHz for the time being.
*/ */
static unsigned int speedstep_low_freq;
static unsigned int speedstep_high_freq;
#define SPEEDSTEP_HIGH 0x00000000 #define SPEEDSTEP_HIGH 0x00000000
#define SPEEDSTEP_LOW 0x00000001 #define SPEEDSTEP_LOW 0x00000001
static struct cpufreq_frequency_table speedstep_freqs[] = {
{SPEEDSTEP_HIGH, 0},
{SPEEDSTEP_LOW, 0},
{0, CPUFREQ_TABLE_END},
};
#define speedstep_low_freq speedstep_freqs[SPEEDSTEP_LOW].frequency
#define speedstep_high_freq speedstep_freqs[SPEEDSTEP_HIGH].frequency
/* DEBUG /* DEBUG
* Define it if you want verbose debug output, e.g. for bug reporting * Define it if you want verbose debug output, e.g. for bug reporting
...@@ -569,22 +575,13 @@ static int speedstep_detect_speeds (void) ...@@ -569,22 +575,13 @@ static int speedstep_detect_speeds (void)
*/ */
static int speedstep_setpolicy (struct cpufreq_policy *policy) static int speedstep_setpolicy (struct cpufreq_policy *policy)
{ {
if (!speedstep_driver || !policy) unsigned int newstate = 0;
if (cpufreq_frequency_table_setpolicy(policy, &speedstep_freqs[0], &newstate))
return -EINVAL; return -EINVAL;
if (policy->min > speedstep_low_freq) speedstep_set_state(newstate, 1);
speedstep_set_state(SPEEDSTEP_HIGH, 1);
else {
if (policy->max < speedstep_high_freq)
speedstep_set_state(SPEEDSTEP_LOW, 1);
else {
/* both frequency states are allowed */
if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
speedstep_set_state(SPEEDSTEP_LOW, 1);
else
speedstep_set_state(SPEEDSTEP_HIGH, 1);
}
}
return 0; return 0;
} }
...@@ -598,19 +595,7 @@ static int speedstep_setpolicy (struct cpufreq_policy *policy) ...@@ -598,19 +595,7 @@ static int speedstep_setpolicy (struct cpufreq_policy *policy)
*/ */
static int speedstep_verify (struct cpufreq_policy *policy) static int speedstep_verify (struct cpufreq_policy *policy)
{ {
if (!policy || !speedstep_driver || return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
!speedstep_low_freq || !speedstep_high_freq)
return -EINVAL;
policy->cpu = 0; /* UP only */
cpufreq_verify_within_limits(policy, speedstep_low_freq, speedstep_high_freq);
if ((policy->min > speedstep_low_freq) &&
(policy->max < speedstep_high_freq))
policy->max = speedstep_high_freq;
return 0;
} }
...@@ -692,6 +677,13 @@ static int __init speedstep_init(void) ...@@ -692,6 +677,13 @@ static int __init speedstep_init(void)
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
driver->policy[0].cpu = 0;
result = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &speedstep_freqs[0]);
if (result) {
kfree(driver);
return result;
}
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = speed; driver->cpu_cur_freq[0] = speed;
#endif #endif
...@@ -699,11 +691,6 @@ static int __init speedstep_init(void) ...@@ -699,11 +691,6 @@ static int __init speedstep_init(void)
driver->verify = &speedstep_verify; driver->verify = &speedstep_verify;
driver->setpolicy = &speedstep_setpolicy; driver->setpolicy = &speedstep_setpolicy;
driver->policy[0].cpu = 0;
driver->policy[0].min = speedstep_low_freq;
driver->policy[0].max = speedstep_high_freq;
driver->policy[0].cpuinfo.min_freq = speedstep_low_freq;
driver->policy[0].cpuinfo.max_freq = speedstep_high_freq;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->policy[0].policy = (speed == speedstep_low_freq) ? driver->policy[0].policy = (speed == speedstep_low_freq) ?
......
...@@ -241,4 +241,27 @@ enum { ...@@ -241,4 +241,27 @@ enum {
#endif /* CONFIG_CPU_FREQ_24_API */ #endif /* CONFIG_CPU_FREQ_24_API */
/*********************************************************************
* FREQUENCY TABLE HELPERS *
*********************************************************************/
#define CPUFREQ_ENTRY_INVALID ~0
#define CPUFREQ_TABLE_END ~1
struct cpufreq_frequency_table {
unsigned int index; /* any */
unsigned int frequency; /* kHz - doesn't need to be in ascending
* order */
};
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table);
int cpufreq_frequency_table_setpolicy(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int *index);
#endif /* _LINUX_CPUFREQ_H */ #endif /* _LINUX_CPUFREQ_H */
...@@ -1134,3 +1134,120 @@ EXPORT_SYMBOL_GPL(cpufreq_restore); ...@@ -1134,3 +1134,120 @@ EXPORT_SYMBOL_GPL(cpufreq_restore);
#define cpufreq_restore() do {} while (0) #define cpufreq_restore() do {} while (0)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
/*********************************************************************
* FREQUENCY TABLE HELPERS *
*********************************************************************/
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
unsigned int i = 0;
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if (freq < min_freq)
min_freq = freq;
if (freq > max_freq)
max_freq = freq;
}
policy->min = policy->cpuinfo.min_freq = min_freq;
policy->max = policy->cpuinfo.max_freq = max_freq;
if (policy->min == ~0)
return -EINVAL;
else
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
unsigned int next_larger = ~0;
unsigned int i = 0;
unsigned int count = 0;
if (!cpu_online(policy->cpu))
return -EINVAL;
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if ((freq >= policy->min) && (freq <= policy->max))
count++;
else if ((next_larger > freq) && (freq > policy->max))
next_larger = freq;
}
if (!count)
policy->max = next_larger;
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
int cpufreq_frequency_table_setpolicy(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int *index)
{
struct cpufreq_frequency_table optimal = { .index = ~0, };
unsigned int i;
switch (policy->policy) {
case CPUFREQ_POLICY_PERFORMANCE:
optimal.frequency = 0;
break;
case CPUFREQ_POLICY_POWERSAVE:
optimal.frequency = ~0;
break;
}
if (!cpu_online(policy->cpu))
return -EINVAL;
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if ((freq < policy->min) || (freq > policy->max))
continue;
switch(policy->policy) {
case CPUFREQ_POLICY_PERFORMANCE:
if (optimal.frequency <= freq) {
optimal.frequency = freq;
optimal.index = i;
}
break;
case CPUFREQ_POLICY_POWERSAVE:
if (optimal.frequency >= freq) {
optimal.frequency = freq;
optimal.index = i;
}
break;
}
}
if (optimal.index > i)
return -EINVAL;
*index = optimal.index;
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_setpolicy);
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