Skip to content

Commit

Permalink
Merge tag 'pm+acpi-fixes-3.9-rc1' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/rafael/linux-pm

Pull ACPI and power management fixes from Rafael Wysocki:

 - Fixes for blackfin and microblaze build problems introduced by the
   removal of global pm_idle.  From Lars-Peter Clausen.

 - OPP core build fix from Shawn Guo.

 - Error condition check fix for the new imx6q-cpufreq driver from Wei
   Yongjun.

 - Fix for an AER driver crash related to the lack of APEI
   initialization for acpi=off.  From Rafael J Wysocki.

 - Fix for a USB breakage on Thinkpad T430 related to ACPI power
   resources and PCI wakeup from Rafael J.  Wysocki.

* tag 'pm+acpi-fixes-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / PM: Take unusual configurations of power resources into account
  imx6q-cpufreq: fix return value check in imx6q_cpufreq_probe()
  PM / OPP: fix condition for empty of_init_opp_table()
  ACPI / APEI: Fix crash in apei_hest_parse() for acpi=off
  microblaze idle: Fix compile error
  blackfin idle: Fix compile error
  • Loading branch information
Linus Torvalds committed Feb 26, 2013
2 parents 556f12f + 4383822 commit c41b381
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 50 deletions.
4 changes: 1 addition & 3 deletions arch/blackfin/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,10 @@ void cpu_idle(void)
if (cpu_is_offline(smp_processor_id()))
cpu_die();
#endif
if (!idle)
idle = default_idle;
tick_nohz_idle_enter();
rcu_idle_enter();
while (!need_resched())
idle();
default_idle();
rcu_idle_exit();
tick_nohz_idle_exit();
preempt_enable_no_resched();
Expand Down
5 changes: 1 addition & 4 deletions arch/microblaze/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,10 @@ void cpu_idle(void)

/* endless idle loop with no priority at all */
while (1) {
if (!idle)
idle = default_idle;

tick_nohz_idle_enter();
rcu_idle_enter();
while (!need_resched())
idle();
default_idle();
rcu_idle_exit();
tick_nohz_idle_exit();

Expand Down
5 changes: 1 addition & 4 deletions drivers/acpi/apei/hest.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ int apei_hest_parse(apei_hest_func_t func, void *data)
struct acpi_hest_header *hest_hdr;
int i, rc, len;

if (hest_disable)
if (hest_disable || !hest_tab)
return -EINVAL;

hest_hdr = (struct acpi_hest_header *)(hest_tab + 1);
Expand Down Expand Up @@ -216,9 +216,6 @@ void __init acpi_hest_init(void)
return;
}

if (acpi_disabled)
goto err;

status = acpi_get_table(ACPI_SIG_HEST, 0,
(struct acpi_table_header **)&hest_tab);
if (status == AE_NOT_FOUND)
Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
struct list_head *list);
int acpi_add_power_resource(acpi_handle handle);
void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
int acpi_power_min_system_level(struct list_head *list);
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level);
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state);
int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
Expand Down
112 changes: 85 additions & 27 deletions drivers/acpi/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct acpi_power_resource {
u32 system_level;
u32 order;
unsigned int ref_count;
bool wakeup_enabled;
struct mutex resource_lock;
};

Expand Down Expand Up @@ -272,11 +273,9 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
return 0;
}

static int acpi_power_on(struct acpi_power_resource *resource)
static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
{
int result = 0;;

mutex_lock(&resource->resource_lock);
int result = 0;

if (resource->ref_count++) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
Expand All @@ -293,9 +292,16 @@ static int acpi_power_on(struct acpi_power_resource *resource)
schedule_work(&dep->work);
}
}
return result;
}

mutex_unlock(&resource->resource_lock);
static int acpi_power_on(struct acpi_power_resource *resource)
{
int result;

mutex_lock(&resource->resource_lock);
result = acpi_power_on_unlocked(resource);
mutex_unlock(&resource->resource_lock);
return result;
}

Expand All @@ -313,17 +319,15 @@ static int __acpi_power_off(struct acpi_power_resource *resource)
return 0;
}

static int acpi_power_off(struct acpi_power_resource *resource)
static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
{
int result = 0;

mutex_lock(&resource->resource_lock);

if (!resource->ref_count) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Power resource [%s] already off",
resource->name));
goto unlock;
return 0;
}

if (--resource->ref_count) {
Expand All @@ -335,10 +339,16 @@ static int acpi_power_off(struct acpi_power_resource *resource)
if (result)
resource->ref_count++;
}
return result;
}

unlock:
mutex_unlock(&resource->resource_lock);
static int acpi_power_off(struct acpi_power_resource *resource)
{
int result;

mutex_lock(&resource->resource_lock);
result = acpi_power_off_unlocked(resource);
mutex_unlock(&resource->resource_lock);
return result;
}

Expand Down Expand Up @@ -521,18 +531,35 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
}
}

int acpi_power_min_system_level(struct list_head *list)
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
{
struct acpi_power_resource_entry *entry;
int system_level = 5;

list_for_each_entry(entry, list, node) {
struct acpi_power_resource *resource = entry->resource;
acpi_handle handle = resource->device.handle;
int result;
int state;

mutex_lock(&resource->resource_lock);

result = acpi_power_get_state(handle, &state);
if (result) {
mutex_unlock(&resource->resource_lock);
return result;
}
if (state == ACPI_POWER_RESOURCE_STATE_ON) {
resource->ref_count++;
resource->wakeup_enabled = true;
}
if (system_level > resource->system_level)
system_level = resource->system_level;

mutex_unlock(&resource->resource_lock);
}
return system_level;
*system_level_p = system_level;
return 0;
}

/* --------------------------------------------------------------------------
Expand Down Expand Up @@ -610,6 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
*/
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{
struct acpi_power_resource_entry *entry;
int err = 0;

if (!dev || !dev->wakeup.flags.valid)
Expand All @@ -620,17 +648,31 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
if (dev->wakeup.prepare_count++)
goto out;

err = acpi_power_on_list(&dev->wakeup.resources);
if (err) {
dev_err(&dev->dev, "Cannot turn wakeup power resources on\n");
dev->wakeup.flags.valid = 0;
} else {
/*
* Passing 3 as the third argument below means the device may be
* put into arbitrary power state afterward.
*/
err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
list_for_each_entry(entry, &dev->wakeup.resources, node) {
struct acpi_power_resource *resource = entry->resource;

mutex_lock(&resource->resource_lock);

if (!resource->wakeup_enabled) {
err = acpi_power_on_unlocked(resource);
if (!err)
resource->wakeup_enabled = true;
}

mutex_unlock(&resource->resource_lock);

if (err) {
dev_err(&dev->dev,
"Cannot turn wakeup power resources on\n");
dev->wakeup.flags.valid = 0;
goto out;
}
}
/*
* Passing 3 as the third argument below means the device may be
* put into arbitrary power state afterward.
*/
err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
if (err)
dev->wakeup.prepare_count = 0;

Expand All @@ -647,6 +689,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
*/
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
{
struct acpi_power_resource_entry *entry;
int err = 0;

if (!dev || !dev->wakeup.flags.valid)
Expand All @@ -668,10 +711,25 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
if (err)
goto out;

err = acpi_power_off_list(&dev->wakeup.resources);
if (err) {
dev_err(&dev->dev, "Cannot turn wakeup power resources off\n");
dev->wakeup.flags.valid = 0;
list_for_each_entry(entry, &dev->wakeup.resources, node) {
struct acpi_power_resource *resource = entry->resource;

mutex_lock(&resource->resource_lock);

if (resource->wakeup_enabled) {
err = acpi_power_off_unlocked(resource);
if (!err)
resource->wakeup_enabled = false;
}

mutex_unlock(&resource->resource_lock);

if (err) {
dev_err(&dev->dev,
"Cannot turn wakeup power resources off\n");
dev->wakeup.flags.valid = 0;
break;
}
}

out:
Expand Down
9 changes: 8 additions & 1 deletion drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,14 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
if (!list_empty(&wakeup->resources)) {
int sleep_state;

sleep_state = acpi_power_min_system_level(&wakeup->resources);
err = acpi_power_wakeup_list_init(&wakeup->resources,
&sleep_state);
if (err) {
acpi_handle_warn(handle, "Retrieving current states "
"of wakeup power resources failed\n");
acpi_power_resources_list_free(&wakeup->resources);
goto out;
}
if (sleep_state < wakeup->sleep_state) {
acpi_handle_warn(handle, "Overriding _PRW sleep state "
"(S%d) by S%d from power resources\n",
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/imx6q-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
arm_reg = devm_regulator_get(cpu_dev, "arm");
pu_reg = devm_regulator_get(cpu_dev, "pu");
soc_reg = devm_regulator_get(cpu_dev, "soc");
if (!arm_reg || !pu_reg || !soc_reg) {
if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) {
dev_err(cpu_dev, "failed to get regulators\n");
ret = -ENOENT;
goto put_node;
Expand Down
18 changes: 9 additions & 9 deletions include/linux/opp.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,6 @@ int opp_enable(struct device *dev, unsigned long freq);
int opp_disable(struct device *dev, unsigned long freq);

struct srcu_notifier_head *opp_get_notifier(struct device *dev);

#ifdef CONFIG_OF
int of_init_opp_table(struct device *dev);
#else
static inline int of_init_opp_table(struct device *dev)
{
return -EINVAL;
}
#endif /* CONFIG_OF */
#else
static inline unsigned long opp_get_voltage(struct opp *opp)
{
Expand Down Expand Up @@ -112,6 +103,15 @@ static inline struct srcu_notifier_head *opp_get_notifier(struct device *dev)
}
#endif /* CONFIG_PM_OPP */

#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
int of_init_opp_table(struct device *dev);
#else
static inline int of_init_opp_table(struct device *dev)
{
return -EINVAL;
}
#endif

#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP)
int opp_init_cpufreq_table(struct device *dev,
struct cpufreq_frequency_table **table);
Expand Down

0 comments on commit c41b381

Please sign in to comment.