aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 10:45:39 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 10:45:39 -0700
commitf2d285669aae656dfeafa0bf25e86bbbc5d22329 (patch)
tree4391c45051429c09199d7fd2ca6ca0dd142a5ed6 /drivers/base
parentMerge tag 'acpi-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm (diff)
parentMerge branches 'pm-cpuidle' and 'pm-tools' (diff)
downloadlinux-dev-f2d285669aae656dfeafa0bf25e86bbbc5d22329.tar.xz
linux-dev-f2d285669aae656dfeafa0bf25e86bbbc5d22329.zip
Merge tag 'pm-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki: "These update the cpuidle poll state definition to reduce excessive energy usage related to it, add new CPU ID to the RAPL power capping driver, update the ACPI system suspend code to handle some special cases better, extend the PM core's device links code slightly, add new sysfs attribute for better suspend-to-idle diagnostics and easier hibernation handling, update power management tools and clean up cpufreq quite a bit. Specifics: - Modify the cpuidle poll state implementation to prevent CPUs from staying in the loop in there for excessive times (Rafael Wysocki). - Add Intel Cannon Lake chips support to the RAPL power capping driver (Joe Konno). - Add reference counting to the device links handling code in the PM core (Lukas Wunner). - Avoid reconfiguring GPEs on suspend-to-idle in the ACPI system suspend code (Rafael Wysocki). - Allow devices to be put into deeper low-power states via ACPI if both _SxD and _SxW are missing (Daniel Drake). - Reorganize the core ACPI suspend-to-idle wakeup code to avoid a keyboard wakeup issue on Asus UX331UA (Chris Chiu). - Prevent the PCMCIA library code from aborting suspend-to-idle due to noirq suspend failures resulting from incorrect assumptions (Rafael Wysocki). - Add coupled cpuidle supprt to the Exynos3250 platform (Marek Szyprowski). - Add new sysfs file to make it easier to specify the image storage location during hibernation (Mario Limonciello). - Add sysfs files for collecting suspend-to-idle usage and time statistics for CPU idle states (Rafael Wysocki). - Update the pm-graph utilities (Todd Brandt). - Reduce the kernel log noise related to reporting Low-power Idle constraings by the ACPI system suspend code (Rafael Wysocki). - Make it easier to distinguish dedicated wakeup IRQs in the /proc/interrupts output (Tony Lindgren). - Add the frequency table validation in cpufreq to the core and drop it from a number of cpufreq drivers (Viresh Kumar). - Drop "cooling-{min|max}-level" for CPU nodes from a couple of DT bindings (Viresh Kumar). - Clean up the CPU online error code path in the cpufreq core (Viresh Kumar). - Fix assorted issues in the SCPI, CPPC, mediatek and tegra186 cpufreq drivers (Arnd Bergmann, Chunyu Hu, George Cherian, Viresh Kumar). - Drop memory allocation error messages from a few places in cpufreq and cpuildle drivers (Markus Elfring)" * tag 'pm-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (56 commits) ACPI / PM: Fix keyboard wakeup from suspend-to-idle on ASUS UX331UA cpufreq: CPPC: Use transition_delay_us depending transition_latency PM / hibernate: Change message when writing to /sys/power/resume PM / hibernate: Make passing hibernate offsets more friendly cpuidle: poll_state: Avoid invoking local_clock() too often PM: cpuidle/suspend: Add s2idle usage and time state attributes cpuidle: Enable coupled cpuidle support on Exynos3250 platform cpuidle: poll_state: Add time limit to poll_idle() cpufreq: tegra186: Don't validate the frequency table twice cpufreq: speedstep: Don't validate the frequency table twice cpufreq: sparc: Don't validate the frequency table twice cpufreq: sh: Don't validate the frequency table twice cpufreq: sfi: Don't validate the frequency table twice cpufreq: scpi: Don't validate the frequency table twice cpufreq: sc520: Don't validate the frequency table twice cpufreq: s3c24xx: Don't validate the frequency table twice cpufreq: qoirq: Don't validate the frequency table twice cpufreq: pxa: Don't validate the frequency table twice cpufreq: ppc_cbe: Don't validate the frequency table twice cpufreq: powernow: Don't validate the frequency table twice ...
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/core.c25
-rw-r--r--drivers/base/power/power.h1
-rw-r--r--drivers/base/power/wakeirq.c13
3 files changed, 29 insertions, 10 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5847364f25d9..b610816eb887 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -196,8 +196,10 @@ struct device_link *device_link_add(struct device *consumer,
}
list_for_each_entry(link, &supplier->links.consumers, s_node)
- if (link->consumer == consumer)
+ if (link->consumer == consumer) {
+ kref_get(&link->kref);
goto out;
+ }
link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
@@ -222,6 +224,7 @@ struct device_link *device_link_add(struct device *consumer,
link->consumer = consumer;
INIT_LIST_HEAD(&link->c_node);
link->flags = flags;
+ kref_init(&link->kref);
/* Determine the initial link state. */
if (flags & DL_FLAG_STATELESS) {
@@ -292,8 +295,10 @@ static void __device_link_free_srcu(struct rcu_head *rhead)
device_link_free(container_of(rhead, struct device_link, rcu_head));
}
-static void __device_link_del(struct device_link *link)
+static void __device_link_del(struct kref *kref)
{
+ struct device_link *link = container_of(kref, struct device_link, kref);
+
dev_info(link->consumer, "Dropping the link to %s\n",
dev_name(link->supplier));
@@ -305,8 +310,10 @@ static void __device_link_del(struct device_link *link)
call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
}
#else /* !CONFIG_SRCU */
-static void __device_link_del(struct device_link *link)
+static void __device_link_del(struct kref *kref)
{
+ struct device_link *link = container_of(kref, struct device_link, kref);
+
dev_info(link->consumer, "Dropping the link to %s\n",
dev_name(link->supplier));
@@ -324,13 +331,15 @@ static void __device_link_del(struct device_link *link)
* @link: Device link to delete.
*
* The caller must ensure proper synchronization of this function with runtime
- * PM.
+ * PM. If the link was added multiple times, it needs to be deleted as often.
+ * Care is required for hotplugged devices: Their links are purged on removal
+ * and calling device_link_del() is then no longer allowed.
*/
void device_link_del(struct device_link *link)
{
device_links_write_lock();
device_pm_lock();
- __device_link_del(link);
+ kref_put(&link->kref, __device_link_del);
device_pm_unlock();
device_links_write_unlock();
}
@@ -444,7 +453,7 @@ static void __device_links_no_driver(struct device *dev)
continue;
if (link->flags & DL_FLAG_AUTOREMOVE)
- __device_link_del(link);
+ kref_put(&link->kref, __device_link_del);
else if (link->status != DL_STATE_SUPPLIER_UNBIND)
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
}
@@ -597,13 +606,13 @@ static void device_links_purge(struct device *dev)
list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) {
WARN_ON(link->status == DL_STATE_ACTIVE);
- __device_link_del(link);
+ __device_link_del(&link->kref);
}
list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) {
WARN_ON(link->status != DL_STATE_DORMANT &&
link->status != DL_STATE_NONE);
- __device_link_del(link);
+ __device_link_del(&link->kref);
}
device_links_write_unlock();
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 21244c53e377..86e67e70b509 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -31,6 +31,7 @@ struct wake_irq {
struct device *dev;
unsigned int status;
int irq;
+ const char *name;
};
extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index 6637fc319269..b8fa5c0f2d13 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -112,6 +112,7 @@ void dev_pm_clear_wake_irq(struct device *dev)
free_irq(wirq->irq, wirq);
wirq->status &= ~WAKE_IRQ_DEDICATED_MASK;
}
+ kfree(wirq->name);
kfree(wirq);
}
EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
@@ -184,6 +185,12 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
if (!wirq)
return -ENOMEM;
+ wirq->name = kasprintf(GFP_KERNEL, "%s:wakeup", dev_name(dev));
+ if (!wirq->name) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
wirq->dev = dev;
wirq->irq = irq;
irq_set_status_flags(irq, IRQ_NOAUTOEN);
@@ -196,9 +203,9 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
* so we use a threaded irq.
*/
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
- IRQF_ONESHOT, dev_name(dev), wirq);
+ IRQF_ONESHOT, wirq->name, wirq);
if (err)
- goto err_free;
+ goto err_free_name;
err = dev_pm_attach_wake_irq(dev, irq, wirq);
if (err)
@@ -210,6 +217,8 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
err_free_irq:
free_irq(irq, wirq);
+err_free_name:
+ kfree(wirq->name);
err_free:
kfree(wirq);