Commit 1aad08dc authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pm+acpi-3.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management and ACPI fixes from Rafael Wysocki:

 - Additional CPU ID for the intel_pstate driver from Dirk Brandewie.

 - More cpufreq fixes related to ARM big.LITTLE support and locking from
   Viresh Kumar.

 - VIA C7 cpufreq build fix from Rafał Bilski.

 - ACPI power management fix making it possible to use device power
   states regardless of the CONFIG_PM setting from Rafael J Wysocki.

 - New ACPI video blacklist item from Bastian Triller.

* tag 'pm+acpi-3.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / video: Add "Asus UL30A" to ACPI video detect blacklist
  cpufreq: arm_big_little_dt: Instantiate as platform_driver
  cpufreq: arm_big_little_dt: Register driver only if DT has valid data
  cpufreq / e_powersaver: Fix linker error when ACPI processor is a module
  cpufreq / intel_pstate: Add additional supported CPU ID
  cpufreq: Drop rwsem lock around CPUFREQ_GOV_POLICY_EXIT
  ACPI / PM: Allow device power states to be used for CONFIG_PM unset
parents 27a24cfa 5a2bff8d
...@@ -24,7 +24,7 @@ acpi-y += nvs.o ...@@ -24,7 +24,7 @@ acpi-y += nvs.o
# Power management related files # Power management related files
acpi-y += wakeup.o acpi-y += wakeup.o
acpi-y += sleep.o acpi-y += sleep.o
acpi-$(CONFIG_PM) += device_pm.o acpi-y += device_pm.o
acpi-$(CONFIG_ACPI_SLEEP) += proc.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o
......
...@@ -37,68 +37,6 @@ ...@@ -37,68 +37,6 @@
#define _COMPONENT ACPI_POWER_COMPONENT #define _COMPONENT ACPI_POWER_COMPONENT
ACPI_MODULE_NAME("device_pm"); ACPI_MODULE_NAME("device_pm");
static DEFINE_MUTEX(acpi_pm_notifier_lock);
/**
* acpi_add_pm_notifier - Register PM notifier for given ACPI device.
* @adev: ACPI device to add the notifier for.
* @context: Context information to pass to the notifier routine.
*
* NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
* PM wakeup events. For example, wakeup events may be generated for bridges
* if one of the devices below the bridge is signaling wakeup, even if the
* bridge itself doesn't have a wakeup GPE associated with it.
*/
acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
acpi_notify_handler handler, void *context)
{
acpi_status status = AE_ALREADY_EXISTS;
mutex_lock(&acpi_pm_notifier_lock);
if (adev->wakeup.flags.notifier_present)
goto out;
status = acpi_install_notify_handler(adev->handle,
ACPI_SYSTEM_NOTIFY,
handler, context);
if (ACPI_FAILURE(status))
goto out;
adev->wakeup.flags.notifier_present = true;
out:
mutex_unlock(&acpi_pm_notifier_lock);
return status;
}
/**
* acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
* @adev: ACPI device to remove the notifier from.
*/
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
acpi_notify_handler handler)
{
acpi_status status = AE_BAD_PARAMETER;
mutex_lock(&acpi_pm_notifier_lock);
if (!adev->wakeup.flags.notifier_present)
goto out;
status = acpi_remove_notify_handler(adev->handle,
ACPI_SYSTEM_NOTIFY,
handler);
if (ACPI_FAILURE(status))
goto out;
adev->wakeup.flags.notifier_present = false;
out:
mutex_unlock(&acpi_pm_notifier_lock);
return status;
}
/** /**
* acpi_power_state_string - String representation of ACPI device power state. * acpi_power_state_string - String representation of ACPI device power state.
* @state: ACPI device power state to return the string representation of. * @state: ACPI device power state to return the string representation of.
...@@ -385,6 +323,69 @@ bool acpi_bus_power_manageable(acpi_handle handle) ...@@ -385,6 +323,69 @@ bool acpi_bus_power_manageable(acpi_handle handle)
} }
EXPORT_SYMBOL(acpi_bus_power_manageable); EXPORT_SYMBOL(acpi_bus_power_manageable);
#ifdef CONFIG_PM
static DEFINE_MUTEX(acpi_pm_notifier_lock);
/**
* acpi_add_pm_notifier - Register PM notifier for given ACPI device.
* @adev: ACPI device to add the notifier for.
* @context: Context information to pass to the notifier routine.
*
* NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
* PM wakeup events. For example, wakeup events may be generated for bridges
* if one of the devices below the bridge is signaling wakeup, even if the
* bridge itself doesn't have a wakeup GPE associated with it.
*/
acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
acpi_notify_handler handler, void *context)
{
acpi_status status = AE_ALREADY_EXISTS;
mutex_lock(&acpi_pm_notifier_lock);
if (adev->wakeup.flags.notifier_present)
goto out;
status = acpi_install_notify_handler(adev->handle,
ACPI_SYSTEM_NOTIFY,
handler, context);
if (ACPI_FAILURE(status))
goto out;
adev->wakeup.flags.notifier_present = true;
out:
mutex_unlock(&acpi_pm_notifier_lock);
return status;
}
/**
* acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
* @adev: ACPI device to remove the notifier from.
*/
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
acpi_notify_handler handler)
{
acpi_status status = AE_BAD_PARAMETER;
mutex_lock(&acpi_pm_notifier_lock);
if (!adev->wakeup.flags.notifier_present)
goto out;
status = acpi_remove_notify_handler(adev->handle,
ACPI_SYSTEM_NOTIFY,
handler);
if (ACPI_FAILURE(status))
goto out;
adev->wakeup.flags.notifier_present = false;
out:
mutex_unlock(&acpi_pm_notifier_lock);
return status;
}
bool acpi_bus_can_wakeup(acpi_handle handle) bool acpi_bus_can_wakeup(acpi_handle handle)
{ {
struct acpi_device *device; struct acpi_device *device;
...@@ -1023,3 +1024,4 @@ void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev) ...@@ -1023,3 +1024,4 @@ void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
mutex_unlock(&adev->physical_node_lock); mutex_unlock(&adev->physical_node_lock);
} }
EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent); EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
#endif /* CONFIG_PM */
...@@ -161,6 +161,14 @@ static struct dmi_system_id video_detect_dmi_table[] = { ...@@ -161,6 +161,14 @@ static struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
}, },
}, },
{
.callback = video_detect_force_vendor,
.ident = "Asus UL30A",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
},
},
{ }, { },
}; };
......
...@@ -272,7 +272,7 @@ config X86_LONGHAUL ...@@ -272,7 +272,7 @@ config X86_LONGHAUL
config X86_E_POWERSAVER config X86_E_POWERSAVER
tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)" tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)"
select CPU_FREQ_TABLE select CPU_FREQ_TABLE
depends on X86_32 depends on X86_32 && ACPI_PROCESSOR
help help
This adds the CPUFreq driver for VIA C7 processors. However, this driver This adds the CPUFreq driver for VIA C7 processors. However, this driver
does not have any safeguards to prevent operating the CPU out of spec does not have any safeguards to prevent operating the CPU out of spec
......
...@@ -19,70 +19,75 @@ ...@@ -19,70 +19,75 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpu.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/opp.h> #include <linux/opp.h>
#include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include "arm_big_little.h" #include "arm_big_little.h"
static int dt_init_opp_table(struct device *cpu_dev) /* get cpu node with valid operating-points */
static struct device_node *get_cpu_node_with_valid_op(int cpu)
{ {
struct device_node *np, *parent; struct device_node *np = NULL, *parent;
int count = 0, ret; int count = 0;
parent = of_find_node_by_path("/cpus"); parent = of_find_node_by_path("/cpus");
if (!parent) { if (!parent) {
pr_err("failed to find OF /cpus\n"); pr_err("failed to find OF /cpus\n");
return -ENOENT; return NULL;
} }
for_each_child_of_node(parent, np) { for_each_child_of_node(parent, np) {
if (count++ != cpu_dev->id) if (count++ != cpu)
continue; continue;
if (!of_get_property(np, "operating-points", NULL)) { if (!of_get_property(np, "operating-points", NULL)) {
ret = -ENODATA; of_node_put(np);
} else { np = NULL;
}
break;
}
of_node_put(parent);
return np;
}
static int dt_init_opp_table(struct device *cpu_dev)
{
struct device_node *np;
int ret;
np = get_cpu_node_with_valid_op(cpu_dev->id);
if (!np)
return -ENODATA;
cpu_dev->of_node = np; cpu_dev->of_node = np;
ret = of_init_opp_table(cpu_dev); ret = of_init_opp_table(cpu_dev);
}
of_node_put(np); of_node_put(np);
of_node_put(parent);
return ret; return ret;
}
return -ENODEV;
} }
static int dt_get_transition_latency(struct device *cpu_dev) static int dt_get_transition_latency(struct device *cpu_dev)
{ {
struct device_node *np, *parent; struct device_node *np;
u32 transition_latency = CPUFREQ_ETERNAL; u32 transition_latency = CPUFREQ_ETERNAL;
int count = 0;
parent = of_find_node_by_path("/cpus"); np = get_cpu_node_with_valid_op(cpu_dev->id);
if (!parent) { if (!np)
pr_info("Failed to find OF /cpus. Use CPUFREQ_ETERNAL transition latency\n");
return CPUFREQ_ETERNAL; return CPUFREQ_ETERNAL;
}
for_each_child_of_node(parent, np) {
if (count++ != cpu_dev->id)
continue;
of_property_read_u32(np, "clock-latency", &transition_latency); of_property_read_u32(np, "clock-latency", &transition_latency);
of_node_put(np); of_node_put(np);
of_node_put(parent);
pr_debug("%s: clock-latency: %d\n", __func__, transition_latency);
return transition_latency; return transition_latency;
}
pr_info("clock-latency isn't found, use CPUFREQ_ETERNAL transition latency\n");
return CPUFREQ_ETERNAL;
} }
static struct cpufreq_arm_bL_ops dt_bL_ops = { static struct cpufreq_arm_bL_ops dt_bL_ops = {
...@@ -91,17 +96,33 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = { ...@@ -91,17 +96,33 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = {
.init_opp_table = dt_init_opp_table, .init_opp_table = dt_init_opp_table,
}; };
static int generic_bL_init(void) static int generic_bL_probe(struct platform_device *pdev)
{ {
struct device_node *np;
np = get_cpu_node_with_valid_op(0);
if (!np)
return -ENODEV;
of_node_put(np);
return bL_cpufreq_register(&dt_bL_ops); return bL_cpufreq_register(&dt_bL_ops);
} }
module_init(generic_bL_init);
static void generic_bL_exit(void) static int generic_bL_remove(struct platform_device *pdev)
{ {
return bL_cpufreq_unregister(&dt_bL_ops); bL_cpufreq_unregister(&dt_bL_ops);
return 0;
} }
module_exit(generic_bL_exit);
static struct platform_driver generic_bL_platdrv = {
.driver = {
.name = "arm-bL-cpufreq-dt",
.owner = THIS_MODULE,
},
.probe = generic_bL_probe,
.remove = generic_bL_remove,
};
module_platform_driver(generic_bL_platdrv);
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT"); MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
......
...@@ -1729,18 +1729,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, ...@@ -1729,18 +1729,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
/* end old governor */ /* end old governor */
if (data->governor) { if (data->governor) {
__cpufreq_governor(data, CPUFREQ_GOV_STOP); __cpufreq_governor(data, CPUFREQ_GOV_STOP);
unlock_policy_rwsem_write(policy->cpu);
__cpufreq_governor(data, __cpufreq_governor(data,
CPUFREQ_GOV_POLICY_EXIT); CPUFREQ_GOV_POLICY_EXIT);
lock_policy_rwsem_write(policy->cpu);
} }
/* start new governor */ /* start new governor */
data->governor = policy->governor; data->governor = policy->governor;
if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) {
failed = 0; failed = 0;
else } else {
unlock_policy_rwsem_write(policy->cpu);
__cpufreq_governor(data, __cpufreq_governor(data,
CPUFREQ_GOV_POLICY_EXIT); CPUFREQ_GOV_POLICY_EXIT);
lock_policy_rwsem_write(policy->cpu);
}
} }
if (failed) { if (failed) {
......
...@@ -521,6 +521,7 @@ static void intel_pstate_timer_func(unsigned long __data) ...@@ -521,6 +521,7 @@ static void intel_pstate_timer_func(unsigned long __data)
static const struct x86_cpu_id intel_pstate_cpu_ids[] = { static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x2a, default_policy), ICPU(0x2a, default_policy),
ICPU(0x2d, default_policy), ICPU(0x2d, default_policy),
ICPU(0x3a, default_policy),
{} {}
}; };
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
......
...@@ -377,7 +377,6 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle, ...@@ -377,7 +377,6 @@ acpi_status acpi_bus_get_status_handle(acpi_handle handle,
unsigned long long *sta); unsigned long long *sta);
int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_get_status(struct acpi_device *device);
#ifdef CONFIG_PM
int acpi_bus_set_power(acpi_handle handle, int state); int acpi_bus_set_power(acpi_handle handle, int state);
const char *acpi_power_state_string(int state); const char *acpi_power_state_string(int state);
int acpi_device_get_power(struct acpi_device *device, int *state); int acpi_device_get_power(struct acpi_device *device, int *state);
...@@ -385,41 +384,12 @@ int acpi_device_set_power(struct acpi_device *device, int state); ...@@ -385,41 +384,12 @@ int acpi_device_set_power(struct acpi_device *device, int state);
int acpi_bus_init_power(struct acpi_device *device); int acpi_bus_init_power(struct acpi_device *device);
int acpi_bus_update_power(acpi_handle handle, int *state_p); int acpi_bus_update_power(acpi_handle handle, int *state_p);
bool acpi_bus_power_manageable(acpi_handle handle); bool acpi_bus_power_manageable(acpi_handle handle);
#ifdef CONFIG_PM
bool acpi_bus_can_wakeup(acpi_handle handle); bool acpi_bus_can_wakeup(acpi_handle handle);
#else /* !CONFIG_PM */ #else
static inline int acpi_bus_set_power(acpi_handle handle, int state) static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
{ #endif
return 0;
}
static inline const char *acpi_power_state_string(int state)
{
return "D0";
}
static inline int acpi_device_get_power(struct acpi_device *device, int *state)
{
return 0;
}
static inline int acpi_device_set_power(struct acpi_device *device, int state)
{
return 0;
}
static inline int acpi_bus_init_power(struct acpi_device *device)
{
return 0;
}
static inline int acpi_bus_update_power(acpi_handle handle, int *state_p)
{
return 0;
}
static inline bool acpi_bus_power_manageable(acpi_handle handle)
{
return false;
}
static inline bool acpi_bus_can_wakeup(acpi_handle handle)
{
return false;
}
#endif /* !CONFIG_PM */
#ifdef CONFIG_ACPI_PROC_EVENT #ifdef CONFIG_ACPI_PROC_EVENT
int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
......
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