projects/linux·commit d5fe85af

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

d5fe85af · Linus Torvalds <[email protected]> · 2013-05-16 15:12:34 -07:00

Pull power management and ACPI fixes from Rafael Wysocki:

 - intel_pstate driver fixes and cleanups from Dirk Brandewie and Wei
   Yongjun.

 - cpufreq fixes related to ARM big.LITTLE support and the cpufreq-cpu0
   driver from Viresh Kumar.

 - Assorted cpufreq fixes from Srivatsa S Bhat, Borislav Petkov, Wolfram
   Sang, Alexander Shiyan, and Nishanth Menon.

 - Assorted ACPI fixes from Catalin Marinas, Lan Tianyu, Alex Hung,
   Jan-Simon Möller, and Rafael J Wysocki.

 - Fix for a kfree() under spinlock in the PM core from Shuah Khan.

 - PM documentation updates from Borislav Petkov and Zhang Rui.

* tag 'pm+acpi-3.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (30 commits)
  cpufreq: Preserve sysfs files across suspend/resume
  ACPI / scan: Fix memory leak on acpi_scan_init_hotplug() error path
  PM / hibernate: Correct documentation
  PM / Documentation: remove inaccurate suspend/hibernate transition lantency statement
  PM: Documentation update for freeze state
  cpufreq / intel_pstate: use vzalloc() instead of vmalloc()/memset(0)
  cpufreq, ondemand: Remove leftover debug line
  PM: Avoid calling kfree() under spinlock in dev_pm_put_subsys_data()
  cpufreq / kirkwood: don't check resource with devm_ioremap_resource
  cpufreq / intel_pstate: remove #ifdef MODULE compile fence
  cpufreq / intel_pstate: Remove idle mode PID
  cpufreq / intel_pstate: fix ffmpeg regression
  cpufreq / intel_pstate: use lowest requested max performance
  cpufreq / intel_pstate: remove idle time and duration from sample and calculations
  cpufreq: Fix incorrect dependecies for ARM SA11xx drivers
  cpufreq: ARM big LITTLE: Fix Kconfig entries
  cpufreq: cpufreq-cpu0: Free parent node for error cases
  cpufreq: cpufreq-cpu0: defer probe when regulator is not ready
  cpufreq: Issue CPUFREQ_GOV_POLICY_EXIT notifier before dropping policy refcount
  cpufreq: governors: Fix CPUFREQ_GOV_POLICY_{INIT|EXIT} notifiers
  ...
Commit
d5fe85af85367d5892e4308f596de4e2a5fb9017
Parents
89682165 · 49a9e431

Merge commit. Changes below are compared with the first parent: 89682165.

Changes

26 files changed · +190 −195

Only the first 600 diff lines are shown. Download the complete patch.

Documentation/power/devices.txt

View file
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 504dfe4..a66c982 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -268,7 +268,7 @@ situations.
System Power Management Phases
------------------------------
Suspending or resuming the system is done in several phases. Different phases
-are used for standby or memory sleep states ("suspend-to-RAM") and the
+are used for freeze, standby, and memory sleep states ("suspend-to-RAM") and the
hibernation state ("suspend-to-disk"). Each phase involves executing callbacks
for every device before the next phase begins. Not all busses or classes
support all these callbacks and not all drivers use all the callbacks. The
@@ -309,7 +309,8 @@ execute the corresponding method from dev->driver->pm instead if there is one.
Entering System Suspend
-----------------------
-When the system goes into the standby or memory sleep state, the phases are:
+When the system goes into the freeze, standby or memory sleep state,
+the phases are:
prepare, suspend, suspend_late, suspend_noirq.
@@ -368,7 +369,7 @@ the devices that were suspended.
Leaving System Suspend
----------------------
-When resuming from standby or memory sleep, the phases are:
+When resuming from freeze, standby or memory sleep, the phases are:
resume_noirq, resume_early, resume, complete.
@@ -433,8 +434,8 @@ the system log.
Entering Hibernation
--------------------
-Hibernating the system is more complicated than putting it into the standby or
-memory sleep state, because it involves creating and saving a system image.
+Hibernating the system is more complicated than putting it into the other
+sleep states, because it involves creating and saving a system image.
Therefore there are more phases for hibernation, with a different set of
callbacks. These phases always run after tasks have been frozen and memory has
been freed.
@@ -485,8 +486,8 @@ image forms an atomic snapshot of the system state.
At this point the system image is saved, and the devices then need to be
prepared for the upcoming system shutdown. This is much like suspending them
-before putting the system into the standby or memory sleep state, and the phases
-are similar.
+before putting the system into the freeze, standby or memory sleep state,
+and the phases are similar.
9. The prepare phase is discussed above.

Documentation/power/interface.txt

View file
diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt
index c537834..f1f0f59 100644
--- a/Documentation/power/interface.txt
+++ b/Documentation/power/interface.txt
@@ -7,8 +7,8 @@ running. The interface exists in /sys/power/ directory (assuming sysfs
is mounted at /sys).
/sys/power/state controls system power state. Reading from this file
-returns what states are supported, which is hard-coded to 'standby'
-(Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk'
+returns what states are supported, which is hard-coded to 'freeze',
+'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk'
(Suspend-to-Disk).
Writing to this file one of those strings causes the system to

Documentation/power/notifiers.txt

View file
diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
index c2a4a34..a81fa25 100644
--- a/Documentation/power/notifiers.txt
+++ b/Documentation/power/notifiers.txt
@@ -15,8 +15,10 @@ A suspend/hibernation notifier may be used for this purpose.
The subsystems or drivers having such needs can register suspend notifiers that
will be called upon the following events by the PM core:
-PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will
- be frozen immediately.
+PM_HIBERNATION_PREPARE The system is going to hibernate, tasks will be frozen
+ immediately. This is different from PM_SUSPEND_PREPARE
+ below because here we do additional work between notifiers
+ and drivers freezing.
PM_POST_HIBERNATION The system memory state has been restored from a
hibernation image or an error occurred during

Documentation/power/states.txt

View file
diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt
index 4416b28..442d43d 100644
--- a/Documentation/power/states.txt
+++ b/Documentation/power/states.txt
@@ -2,12 +2,26 @@
System Power Management States
-The kernel supports three power management states generically, though
-each is dependent on platform support code to implement the low-level
-details for each state. This file describes each state, what they are
+The kernel supports four power management states generically, though
+one is generic and the other three are dependent on platform support
+code to implement the low-level details for each state.
+This file describes each state, what they are
commonly called, what ACPI state they map to, and what string to write
to /sys/power/state to enter that state
+state: Freeze / Low-Power Idle
+ACPI state: S0
+String: "freeze"
+
+This state is a generic, pure software, light-weight, low-power state.
+It allows more energy to be saved relative to idle by freezing user
+space and putting all I/O devices into low-power states (possibly
+lower-power than available at run time), such that the processors can
+spend more time in their idle states.
+This state can be used for platforms without Standby/Suspend-to-RAM
+support, or it can be used in addition to Suspend-to-RAM (memory sleep)
+to provide reduced resume latency.
+
State: Standby / Power-On Suspend
ACPI State: S1
@@ -22,9 +36,6 @@ We try to put devices in a low-power state equivalent to D1, which
also offers low power savings, but low resume latency. Not all devices
support D1, and those that don't are left on.
-A transition from Standby to the On state should take about 1-2
-seconds.
-
State: Suspend-to-RAM
ACPI State: S3
@@ -42,9 +53,6 @@ transition back to the On state.
For at least ACPI, STR requires some minimal boot-strapping code to
resume the system from STR. This may be true on other platforms.
-A transition from Suspend-to-RAM to the On state should take about
-3-5 seconds.
-
State: Suspend-to-disk
ACPI State: S4
@@ -74,7 +82,3 @@ low-power state (like ACPI S4), or it may simply power down. Powering
down offers greater savings, and allows this mechanism to work on any
system. However, entering a real low-power state allows the user to
trigger wake up events (e.g. pressing a key or opening a laptop lid).
-
-A transition from Suspend-to-Disk to the On state should take about 30
-seconds, though it's typically a bit more with the current
-implementation.

drivers/acpi/ac.c

View file
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 00d2efd..4f4e741 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -28,6 +28,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/delay.h>
#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -74,6 +76,8 @@ static int acpi_ac_resume(struct device *dev);
#endif
static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
+static int ac_sleep_before_get_state_ms;
+
static struct acpi_driver acpi_ac_driver = {
.name = "ac",
.class = ACPI_AC_CLASS,
@@ -252,6 +256,16 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
case ACPI_AC_NOTIFY_STATUS:
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
+ /*
+ * A buggy BIOS may notify AC first and then sleep for
+ * a specific time before doing actual operations in the
+ * EC event handler (_Qxx). This will cause the AC state
+ * reported by the ACPI event to be incorrect, so wait for a
+ * specific time for the EC event handler to make progress.
+ */
+ if (ac_sleep_before_get_state_ms > 0)
+ msleep(ac_sleep_before_get_state_ms);
+
acpi_ac_get_state(ac);
acpi_bus_generate_proc_event(device, event, (u32) ac->state);
acpi_bus_generate_netlink_event(device->pnp.device_class,
@@ -264,6 +278,24 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
return;
}
+static int thinkpad_e530_quirk(const struct dmi_system_id *d)
+{
+ ac_sleep_before_get_state_ms = 1000;
+ return 0;
+}
+
+static struct dmi_system_id ac_dmi_table[] = {
+ {
+ .callback = thinkpad_e530_quirk,
+ .ident = "thinkpad e530",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"),
+ },
+ },
+ {},
+};
+
static int acpi_ac_add(struct acpi_device *device)
{
int result = 0;
@@ -312,6 +344,7 @@ static int acpi_ac_add(struct acpi_device *device)
kfree(ac);
}
+ dmi_check_system(ac_dmi_table);
return result;
}

drivers/acpi/ec.c

View file
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d45b287..edc0081 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -223,7 +223,7 @@ static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
static int ec_poll(struct acpi_ec *ec)
{
unsigned long flags;
- int repeat = 2; /* number of command restarts */
+ int repeat = 5; /* number of command restarts */
while (repeat--) {
unsigned long delay = jiffies +
msecs_to_jiffies(ec_delay);
@@ -241,8 +241,6 @@ static int ec_poll(struct acpi_ec *ec)
}
advance_transaction(ec, acpi_ec_read_status(ec));
} while (time_before(jiffies, delay));
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
- break;
pr_debug(PREFIX "controller reset, restart transaction\n");
spin_lock_irqsave(&ec->lock, flags);
start_transaction(ec);

drivers/acpi/processor_driver.c

View file
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index bec717f..c266cdc 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -95,9 +95,6 @@ static const struct acpi_device_id processor_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, processor_device_ids);
-static SIMPLE_DEV_PM_OPS(acpi_processor_pm,
- acpi_processor_suspend, acpi_processor_resume);
-
static struct acpi_driver acpi_processor_driver = {
.name = "processor",
.class = ACPI_PROCESSOR_CLASS,
@@ -107,7 +104,6 @@ static struct acpi_driver acpi_processor_driver = {
.remove = acpi_processor_remove,
.notify = acpi_processor_notify,
},
- .drv.pm = &acpi_processor_pm,
};
#define INSTALL_NOTIFY_HANDLER 1
@@ -934,6 +930,8 @@ static int __init acpi_processor_init(void)
if (result < 0)
return result;
+ acpi_processor_syscore_init();
+
acpi_processor_install_hotplug_notify();
acpi_thermal_cpufreq_init();
@@ -956,6 +954,8 @@ static void __exit acpi_processor_exit(void)
acpi_processor_uninstall_hotplug_notify();
+ acpi_processor_syscore_exit();
+
acpi_bus_unregister_driver(&acpi_processor_driver);
return;

drivers/acpi/processor_idle.c

View file
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f0df2c9..eb133c7 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -34,6 +34,7 @@
#include <linux/sched.h> /* need_resched() */
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
+#include <linux/syscore_ops.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
@@ -210,33 +211,41 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
#endif
+#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
-static void acpi_idle_bm_rld_save(void)
+int acpi_processor_suspend(void)
{
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
+ return 0;
}
-static void acpi_idle_bm_rld_restore(void)
+
+void acpi_processor_resume(void)
{
u32 resumed_bm_rld;
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
+ if (resumed_bm_rld == saved_bm_rld)
+ return;
- if (resumed_bm_rld != saved_bm_rld)
- acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
+ acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
}
-int acpi_processor_suspend(struct device *dev)
+static struct syscore_ops acpi_processor_syscore_ops = {
+ .suspend = acpi_processor_suspend,
+ .resume = acpi_processor_resume,
+};
+
+void acpi_processor_syscore_init(void)
{
- acpi_idle_bm_rld_save();
- return 0;
+ register_syscore_ops(&acpi_processor_syscore_ops);
}
-int acpi_processor_resume(struct device *dev)
+void acpi_processor_syscore_exit(void)
{
- acpi_idle_bm_rld_restore();
- return 0;
+ unregister_syscore_ops(&acpi_processor_syscore_ops);
}
+#endif /* CONFIG_PM_SLEEP */
#if defined(CONFIG_X86)
static void tsc_check_state(int state)

drivers/acpi/scan.c

View file
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index fe158fd..c1bc608 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1785,7 +1785,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type)
acpi_set_pnp_ids(handle, &pnp, type);
if (!pnp.type.hardware_id)
- return;
+ goto out;
/*
* This relies on the fact that acpi_install_notify_handler() will not
@@ -1800,6 +1800,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type)
}
}
+out:
acpi_free_pnp_ids(&pnp);
}

drivers/acpi/video.c

View file
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index c3932d0..5b32e15 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -456,6 +456,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dm4 Notebook PC"),
},
},
+ {
+ .callback = video_ignore_initial_backlight,
+ .ident = "HP 1000 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP 1000 Notebook PC"),
+ },
+ },
{}
};

drivers/base/power/common.c

View file
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index 39c3252..5da9140 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -61,24 +61,24 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
int dev_pm_put_subsys_data(struct device *dev)
{
struct pm_subsys_data *psd;
- int ret = 0;
+ int ret = 1;
spin_lock_irq(&dev->power.lock);
psd = dev_to_psd(dev);
- if (!psd) {
- ret = -EINVAL;
+ if (!psd)
goto out;
- }
if (--psd->refcount == 0) {
dev->power.subsys_data = NULL;
- kfree(psd);
- ret = 1;
+ } else {
+ psd = NULL;
+ ret = 0;
}
out:
spin_unlock_irq(&dev->power.lock);
+ kfree(psd);
return ret;
}

drivers/cpufreq/Kconfig

View file
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index a1488f5..534fcb8 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -47,7 +47,7 @@ config CPU_FREQ_STAT_DETAILS
choice
prompt "Default CPUFreq governor"
- default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
+ default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
help
This option sets which CPUFreq governor shall be loaded at

drivers/cpufreq/Kconfig.arm

View file
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index f3af18b..6e57543 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -3,16 +3,17 @@
#
config ARM_BIG_LITTLE_CPUFREQ
- tristate
- depends on ARM_CPU_TOPOLOGY
+ tristate "Generic ARM big LITTLE CPUfreq driver"
+ depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK
+ help
+ This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
config ARM_DT_BL_CPUFREQ
- tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
- select ARM_BIG_LITTLE_CPUFREQ
- depends on OF && HAVE_CLK
+ tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && OF
help
- This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
- This gets frequency tables from DT.
+ This enables probing via DT for Generic CPUfreq driver for ARM
+ big.LITTLE platform. This gets frequency tables from DT.
config ARM_EXYNOS_CPUFREQ
bool "SAMSUNG EXYNOS SoCs"

drivers/cpufreq/arm_big_little.c

View file
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index dbdf677..5d7f53f 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -40,11 +40,6 @@ static struct clk *clk[MAX_CLUSTERS];
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
-static int cpu_to_cluster(int cpu)
-{
- return topology_physical_package_id(cpu);
-}
-
static unsigned int bL_cpufreq_get(unsigned int cpu)
{
u32 cur_cluster = cpu_to_cluster(cpu);
@@ -192,7 +187,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
- dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu);
+ dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu);
return 0;
}

drivers/cpufreq/arm_big_little.h

View file
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
index 70f18fc..79b2ce1 100644
--- a/drivers/cpufreq/arm_big_little.h
+++ b/drivers/cpufreq/arm_big_little.h
@@ -34,6 +34,11 @@ struct cpufreq_arm_bL_ops {
int (*init_opp_table)(struct device *cpu_dev);
};
+static inline int cpu_to_cluster(int cpu)
+{
+ return topology_physical_package_id(cpu);
+}
+
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);

drivers/cpufreq/arm_big_little_dt.c

View file
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
index 44be311..173ed05 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -66,8 +66,8 @@ static int dt_get_transition_latency(struct device *cpu_dev)
parent = of_find_node_by_path("/cpus");
if (!parent) {
- pr_err("failed to find OF /cpus\n");
- return -ENOENT;
+ pr_info("Failed to find OF /cpus. Use CPUFREQ_ETERNAL transition latency\n");
+ return CPUFREQ_ETERNAL;
}
for_each_child_of_node(parent, np) {
@@ -78,10 +78,11 @@ static int dt_get_transition_latency(struct device *cpu_dev)
of_node_put(np);
of_node_put(parent);
- return 0;
+ return transition_latency;
}
- return -ENODEV;
+ 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 = {

drivers/cpufreq/cpufreq-cpu0.c

View file
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 3ab8294..a64eb8b 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -189,12 +189,29 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
if (!np) {
pr_err("failed to find cpu0 node\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto out_put_parent;
}
cpu_dev = &pdev->dev;
cpu_dev->of_node = np;
+ cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
+ if (IS_ERR(cpu_reg)) {
+ /*
+ * If cpu0 regulator supply node is present, but regulator is
+ * not yet registered, we should try defering probe.
+ */
+ if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) {
+ dev_err(cpu_dev, "cpu0 regulator not ready, retry\n");
+ ret = -EPROBE_DEFER;
+ goto out_put_node;
+ }
+ pr_warn("failed to get cpu0 regulator: %ld\n",
+ PTR_ERR(cpu_reg));
+ cpu_reg = NULL;
+ }
+
cpu_clk = devm_clk_get(cpu_dev, NULL);
if (IS_ERR(cpu_clk)) {
ret = PTR_ERR(cpu_clk);
@@ -202,12 +219,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
goto out_put_node;
}
- cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
- if (IS_ERR(cpu_reg)) {
- pr_warn("failed to get cpu0 regulator\n");
- cpu_reg = NULL;
- }
-
ret = of_init_opp_table(cpu_dev);
if (ret) {
pr_err("failed to init OPP table: %d\n", ret);
@@ -264,6 +275,8 @@ out_free_table:
opp_free_cpufreq_table(cpu_dev, &freq_table);
out_put_node:
of_node_put(np);
+out_put_parent:
+ of_node_put(parent);
return ret;
}

drivers/cpufreq/cpufreq.c

View file
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1b8a48e..4b8c7f2 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1075,14 +1075,14 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
__func__, cpu_dev->id, cpu);
}
+ if ((cpus == 1) && (cpufreq_driver->target))
+ __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);

This diff is incomplete. Download the complete patch.

drivers/cpufreq/cpufreq_governor.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/cpufreq_governor.h

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/cpufreq_ondemand.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/cpufreq_stats.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/intel_pstate.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/kirkwood-cpufreq.c

View file

This diff is incomplete. Download the complete patch.

include/acpi/acpiosxf.h

View file

This diff is incomplete. Download the complete patch.

include/acpi/processor.h

View file

This diff is incomplete. Download the complete patch.