ACPI and power management fixes for 3.15-rc4

- 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.
 
 /
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJTZCgMAAoJEILEb/54YlRxfaoQAKHm8FePiu269gZiejU1wA/+
 SpGfqK4Src03ylIguIfZBXIKO30L9ZqWrKxnfAipPFO2zc53KW6Ip25UGvN9Is01
 Sdw/EV1JNh3Su4kZJDXpNj2OjwuE4GyCuNaccaD6H8ns3qpxK0JNEHFww5d+1UzQ
 WdAEbEqe/G+H9Y1gEX8N2yk3wji1h2SPFsD82Lo8F8L2c3qseYMThSG/plnYyPgr
 ZSnw7I2xeNB9a7LsVzNMlkfgYW0Op3uUTWJQbpxkHCEZjrhctdYzg2G9P9lKoYTA
 X7XAChZrYEGwRrRQZ8X8esPBrqLAqkgkQTksQOzFWvXTS2PoiUb+YV0NXYwWfccS
 omASYqMc0dprUnNFCbh4XjeubKGc1x7KuhSGCV+7QjF0ryNt65vMBUM52wwZ/sNk
 1qJjNAiJDKj/mJ2Ova/Jma2sQJR+1KCnPvzITCpBSfZwNugGMKaWPo8evRv98DE4
 EW7lSSNKcIOR4iM2xd4al9IFWtWEJHiiNaRjMGUn6gsyVjsafGt24lbyr3uohTCo
 memzQaH7SLi4AzCBdo8xXd5vOXUPqGGQMoCkp2IEmPm+WDjKTCbcNZhmvZ9j3Swe
 SMU2ScSpr+MTWrG/ITOjD2+iAlOsjWDMLQjZD27du8HSXLs8FV92l+Um2rvlFnzi
 sX3lS1gHLROes3b56fnQ
 =FeTn
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2014-05-02 18:16:31 -07:00
commit 6c6ca9c2a5
8 changed files with 85 additions and 59 deletions

View File

@ -170,6 +170,9 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
acpi_status status;
int ret;
if (pr->apic_id == -1)
return -ENODEV;
status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
return -ENODEV;
@ -260,10 +263,8 @@ static int acpi_processor_get_info(struct acpi_device *device)
}
apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
if (apic_id < 0) {
if (apic_id < 0)
acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n");
return -ENODEV;
}
pr->apic_id = apic_id;
cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);

View File

@ -206,13 +206,13 @@ unlock:
spin_unlock_irqrestore(&ec->lock, flags);
}
static int acpi_ec_sync_query(struct acpi_ec *ec);
static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
{
if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
return acpi_ec_sync_query(ec);
return acpi_ec_sync_query(ec, NULL);
}
return 0;
}
@ -443,10 +443,8 @@ acpi_handle ec_get_handle(void)
EXPORT_SYMBOL(ec_get_handle);
static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
/*
* Clears stale _Q events that might have accumulated in the EC.
* Process _Q events that might have accumulated in the EC.
* Run with locked ec mutex.
*/
static void acpi_ec_clear(struct acpi_ec *ec)
@ -455,7 +453,7 @@ static void acpi_ec_clear(struct acpi_ec *ec)
u8 value = 0;
for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
status = acpi_ec_query_unlocked(ec, &value);
status = acpi_ec_sync_query(ec, &value);
if (status || !value)
break;
}
@ -582,13 +580,18 @@ static void acpi_ec_run(void *cxt)
kfree(handler);
}
static int acpi_ec_sync_query(struct acpi_ec *ec)
static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
{
u8 value = 0;
int status;
struct acpi_ec_query_handler *handler, *copy;
if ((status = acpi_ec_query_unlocked(ec, &value)))
status = acpi_ec_query_unlocked(ec, &value);
if (data)
*data = value;
if (status)
return status;
list_for_each_entry(handler, &ec->list, node) {
if (value == handler->query_bit) {
/* have custom handler for this bit */
@ -612,7 +615,7 @@ static void acpi_ec_gpe_query(void *ec_cxt)
if (!ec)
return;
mutex_lock(&ec->mutex);
acpi_ec_sync_query(ec);
acpi_ec_sync_query(ec, NULL);
mutex_unlock(&ec->mutex);
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -83,8 +83,7 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
{
struct acpi_device *acpi_dev;
acpi_handle handle;
struct acpi_buffer buffer;
int ret;
int ret = 0;
pnp_dbg(&dev->dev, "set resources\n");
@ -97,19 +96,26 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
if (WARN_ON_ONCE(acpi_dev != dev->data))
dev->data = acpi_dev;
ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
ret = pnpacpi_encode_resources(dev, &buffer);
if (ret) {
if (acpi_has_method(handle, METHOD_NAME__SRS)) {
struct acpi_buffer buffer;
ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
ret = pnpacpi_encode_resources(dev, &buffer);
if (!ret) {
acpi_status status;
status = acpi_set_current_resources(handle, &buffer);
if (ACPI_FAILURE(status))
ret = -EIO;
}
kfree(buffer.pointer);
return ret;
}
if (ACPI_FAILURE(acpi_set_current_resources(handle, &buffer)))
ret = -EINVAL;
else if (acpi_bus_power_manageable(handle))
if (!ret && acpi_bus_power_manageable(handle))
ret = acpi_bus_set_power(handle, ACPI_STATE_D0);
kfree(buffer.pointer);
return ret;
}
@ -117,7 +123,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
{
struct acpi_device *acpi_dev;
acpi_handle handle;
int ret;
acpi_status status;
dev_dbg(&dev->dev, "disable resources\n");
@ -128,13 +134,15 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
}
/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
ret = 0;
if (acpi_bus_power_manageable(handle))
acpi_bus_set_power(handle, ACPI_STATE_D3_COLD);
/* continue even if acpi_bus_set_power() fails */
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL)))
ret = -ENODEV;
return ret;
/* continue even if acpi_bus_set_power() fails */
status = acpi_evaluate_object(handle, "_DIS", NULL, NULL);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
return -ENODEV;
return 0;
}
#ifdef CONFIG_ACPI_SLEEP

View File

@ -335,7 +335,7 @@ static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
}
#endif
#ifdef CONFIG_X86
#ifdef CONFIG_PCI
/* Device IDs of parts that have 32KB MCH space */
static const unsigned int mch_quirk_devices[] = {
0x0154, /* Ivy Bridge */
@ -440,7 +440,7 @@ static struct pnp_fixup pnp_fixups[] = {
#ifdef CONFIG_AMD_NB
{"PNP0c01", quirk_amd_mmconfig_area},
#endif
#ifdef CONFIG_X86
#ifdef CONFIG_PCI
{"PNP0c02", quirk_intel_mch},
#endif
{""}