summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-05-03 03:16:31 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2014-05-03 03:16:31 +0200
commit6c6ca9c2a5b97ab37ffd1b091d15eb5cd3f1bf23 (patch)
tree9507946fff33b9b0ea7acfe0ac26ce497dd88d30 /drivers/cpufreq
parentMerge tag 'dt-for-linus' of git://git.secretlab.ca/git/linux (diff)
parentMerge branches 'acpi-ec' and 'acpi-processor' (diff)
downloadlinux-6c6ca9c2a5b97ab37ffd1b091d15eb5cd3f1bf23.tar.xz
linux-6c6ca9c2a5b97ab37ffd1b091d15eb5cd3f1bf23.zip
Merge tag 'pm+acpi-3.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI and power management fixes from Rafael Wysocki: "A bunch of regression fixes this time. They fix two regressions in the PNP subsystem, one in the ACPI processor driver and one in the ACPI EC driver, four cpufreq driver regressions and an unrelated bug in one of the drivers. The regressions are recent or introduced in 3.14. Specifics: - There are two bugs in the ACPI PNP core that cause errors to be returned if optional ACPI methods are not present. After an ACPI core change made in 3.14 one of those errors leads to serial port suspend failures on some systems. Fix from Rafael J Wysocki. - A recently added PNP quirk related to Intel chipsets intorduced a build error in unusual configurations (PNP without PCI). Fix from Bjorn Helgaas. - An ACPI EC workaround related to system suspend on Samsung machines added in 3.14 introduced a race causing some valid EC events to be discarded. Fix from Kieran Clancy. - The acpi-cpufreq driver fails to load on some systems after a 3.14 commit related to APIC ID parsing that overlooked one corner case. Fix from Lan Tianyu. - Fix for a recently introduced build problem in the ppc-corenet cpufreq driver from Tim Gardner. - A recent cpufreq core change to ensure serialization of frequency transitions for drivers with a ->target_index() callback overlooked the fact that some of those drivers had been doing operations introduced by it into the core already by themselves. That resulted in a mess in which the core and the drivers try to do the same thing and block each other which leads to deadlocks. Fixes for the powernow-k7, powernow-k6, and longhaul cpufreq drivers from Srivatsa S Bhat. - Fix for a computational error in the powernow-k6 cpufreq driver from Srivatsa S Bhat" * tag 'pm+acpi-3.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / processor: Fix failure of loading acpi-cpufreq driver PNP / ACPI: Do not return errors if _DIS or _SRS are not present PNP: Fix compile error in quirks.c ACPI / EC: Process rather than discard events in acpi_ec_clear cpufreq: ppc-corenet-cpufreq: Fix __udivdi3 modpost error cpufreq: powernow-k7: Fix double invocation of cpufreq_freq_transition_begin/end cpufreq: powernow-k6: Fix double invocation of cpufreq_freq_transition_begin/end cpufreq: powernow-k6: Fix incorrect comparison with max_multipler cpufreq: longhaul: Fix double invocation of cpufreq_freq_transition_begin/end
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/longhaul.c36
-rw-r--r--drivers/cpufreq/powernow-k6.c23
-rw-r--r--drivers/cpufreq/powernow-k7.c4
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c5
4 files changed, 41 insertions, 27 deletions
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index d00e5d1abd25..5c4369b5d834 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -242,7 +242,7 @@ static void do_powersaver(int cx_address, unsigned int mults_index,
* Sets a new clock ratio.
*/
-static void longhaul_setstate(struct cpufreq_policy *policy,
+static int longhaul_setstate(struct cpufreq_policy *policy,
unsigned int table_index)
{
unsigned int mults_index;
@@ -258,10 +258,12 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
/* Safety precautions */
mult = mults[mults_index & 0x1f];
if (mult == -1)
- return;
+ return -EINVAL;
+
speed = calc_speed(mult);
if ((speed > highest_speed) || (speed < lowest_speed))
- return;
+ return -EINVAL;
+
/* Voltage transition before frequency transition? */
if (can_scale_voltage && longhaul_index < table_index)
dir = 1;
@@ -269,8 +271,6 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
freqs.old = calc_speed(longhaul_get_cpu_mult());
freqs.new = speed;
- cpufreq_freq_transition_begin(policy, &freqs);
-
pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000));
retry_loop:
@@ -385,12 +385,14 @@ retry_loop:
goto retry_loop;
}
}
- /* Report true CPU frequency */
- cpufreq_freq_transition_end(policy, &freqs, 0);
- if (!bm_timeout)
+ if (!bm_timeout) {
printk(KERN_INFO PFX "Warning: Timeout while waiting for "
"idle PCI bus.\n");
+ return -EBUSY;
+ }
+
+ return 0;
}
/*
@@ -631,9 +633,10 @@ static int longhaul_target(struct cpufreq_policy *policy,
unsigned int i;
unsigned int dir = 0;
u8 vid, current_vid;
+ int retval = 0;
if (!can_scale_voltage)
- longhaul_setstate(policy, table_index);
+ retval = longhaul_setstate(policy, table_index);
else {
/* On test system voltage transitions exceeding single
* step up or down were turning motherboard off. Both
@@ -648,7 +651,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
while (i != table_index) {
vid = (longhaul_table[i].driver_data >> 8) & 0x1f;
if (vid != current_vid) {
- longhaul_setstate(policy, i);
+ retval = longhaul_setstate(policy, i);
current_vid = vid;
msleep(200);
}
@@ -657,10 +660,11 @@ static int longhaul_target(struct cpufreq_policy *policy,
else
i--;
}
- longhaul_setstate(policy, table_index);
+ retval = longhaul_setstate(policy, table_index);
}
+
longhaul_index = table_index;
- return 0;
+ return retval;
}
@@ -968,7 +972,15 @@ static void __exit longhaul_exit(void)
for (i = 0; i < numscales; i++) {
if (mults[i] == maxmult) {
+ struct cpufreq_freqs freqs;
+
+ freqs.old = policy->cur;
+ freqs.new = longhaul_table[i].frequency;
+ freqs.flags = 0;
+
+ cpufreq_freq_transition_begin(policy, &freqs);
longhaul_setstate(policy, i);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
break;
}
}
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index 49f120e1bc7b..78904e6ca4a0 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -138,22 +138,14 @@ static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
static int powernow_k6_target(struct cpufreq_policy *policy,
unsigned int best_i)
{
- struct cpufreq_freqs freqs;
if (clock_ratio[best_i].driver_data > max_multiplier) {
printk(KERN_ERR PFX "invalid target frequency\n");
return -EINVAL;
}
- freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
- freqs.new = busfreq * clock_ratio[best_i].driver_data;
-
- cpufreq_freq_transition_begin(policy, &freqs);
-
powernow_k6_set_cpu_multiplier(best_i);
- cpufreq_freq_transition_end(policy, &freqs, 0);
-
return 0;
}
@@ -227,9 +219,20 @@ have_busfreq:
static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
{
unsigned int i;
- for (i = 0; i < 8; i++) {
- if (i == max_multiplier)
+
+ for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
+ if (clock_ratio[i].driver_data == max_multiplier) {
+ struct cpufreq_freqs freqs;
+
+ freqs.old = policy->cur;
+ freqs.new = clock_ratio[i].frequency;
+ freqs.flags = 0;
+
+ cpufreq_freq_transition_begin(policy, &freqs);
powernow_k6_target(policy, i);
+ cpufreq_freq_transition_end(policy, &freqs, 0);
+ break;
+ }
}
return 0;
}
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index f911645c3f6d..e61e224475ad 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -269,8 +269,6 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
freqs.new = powernow_table[index].frequency;
- cpufreq_freq_transition_begin(policy, &freqs);
-
/* Now do the magic poking into the MSRs. */
if (have_a0 == 1) /* A0 errata 5 */
@@ -290,8 +288,6 @@ static int powernow_target(struct cpufreq_policy *policy, unsigned int index)
if (have_a0 == 1)
local_irq_enable();
- cpufreq_freq_transition_end(policy, &freqs, 0);
-
return 0;
}
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index a1ca3dd04a8e..0af618abebaf 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -138,6 +138,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
struct cpufreq_frequency_table *table;
struct cpu_data *data;
unsigned int cpu = policy->cpu;
+ u64 transition_latency_hz;
np = of_get_cpu_node(cpu, NULL);
if (!np)
@@ -205,8 +206,10 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
for_each_cpu(i, per_cpu(cpu_mask, cpu))
per_cpu(cpu_data, i) = data;
+ transition_latency_hz = 12ULL * NSEC_PER_SEC;
policy->cpuinfo.transition_latency =
- (12ULL * NSEC_PER_SEC) / fsl_get_sys_freq();
+ do_div(transition_latency_hz, fsl_get_sys_freq());
+
of_node_put(np);
return 0;