Skip to content

Commit

Permalink
Merge tag 'pm-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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
  ...
  • Loading branch information
torvalds committed Apr 3, 2018
2 parents be55375 + 103cf0e commit f2d2856
Show file tree
Hide file tree
Showing 75 changed files with 2,916 additions and 915 deletions.
25 changes: 25 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-system-cpu
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,31 @@ Description:
time (in microseconds) this cpu should spend in this idle state
to make the transition worth the effort.

What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/s2idle/
Date: March 2018
KernelVersion: v4.17
Contact: Linux power management list <[email protected]>
Description:
Idle state usage statistics related to suspend-to-idle.

This attribute group is only present for states that can be
used in suspend-to-idle with suspended timekeeping.

What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/s2idle/time
Date: March 2018
KernelVersion: v4.17
Contact: Linux power management list <[email protected]>
Description:
Total time spent by the CPU in suspend-to-idle (with scheduler
tick suspended) after requesting this state.

What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/s2idle/usage
Date: March 2018
KernelVersion: v4.17
Contact: Linux power management list <[email protected]>
Description:
Total number of times this state has been requested by the CPU
while entering suspend-to-idle.

What: /sys/devices/system/cpu/cpu#/cpufreq/*
Date: pre-git history
Expand Down
14 changes: 14 additions & 0 deletions Documentation/ABI/testing/sysfs-power
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,17 @@ Description:
Writing a "1" to this file enables the debug messages and
writing a "0" (default) to it disables them. Reads from
this file return the current value.

What: /sys/power/resume_offset
Date: April 2018
Contact: Mario Limonciello <[email protected]>
Description:
This file is used for telling the kernel an offset into a disk
to use when hibernating the system such as with a swap file.

Reads from this file will display the current offset
the kernel will be using on the next hibernation
attempt.

Using this sysfs file will override any values that were
set using the kernel command line for disk offset.
4 changes: 0 additions & 4 deletions Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ Optional properties:
in unit of nanoseconds.
- voltage-tolerance: Specify the CPU voltage tolerance in percentage.
- #cooling-cells:
- cooling-min-level:
- cooling-max-level:
Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.

Examples:
Expand All @@ -40,8 +38,6 @@ cpus {
>;
clock-latency = <61036>; /* two CLK32 periods */
#cooling-cells = <2>;
cooling-min-level = <0>;
cooling-max-level = <2>;
};

cpu@1 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ Optional properties:
flow is handled by hardware, hence no software "voltage tracking" is
needed.
- #cooling-cells:
- cooling-min-level:
- cooling-max-level:
Please refer to Documentation/devicetree/bindings/thermal/thermal.txt
for detail.

Expand Down Expand Up @@ -67,8 +65,6 @@ Example 1 (MT7623 SoC):
clock-names = "cpu", "intermediate";
operating-points-v2 = <&cpu_opp_table>;
#cooling-cells = <2>;
cooling-min-level = <0>;
cooling-max-level = <7>;
};
cpu@1 {
device_type = "cpu";
Expand Down
10 changes: 9 additions & 1 deletion Documentation/power/swsusp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,16 @@ Some warnings, first.
* see the FAQ below for details. (This is not true for more traditional
* power states like "standby", which normally don't turn USB off.)

Swap partition:
You need to append resume=/dev/your_swap_partition to kernel command
line. Then you suspend by
line or specify it using /sys/power/resume.

Swap file:
If using a swapfile you can also specify a resume offset using
resume_offset=<number> on the kernel command line or specify it
in /sys/power/resume_offset.

After preparing then you suspend by

echo shutdown > /sys/power/disk; echo disk > /sys/power/state

Expand Down
2 changes: 0 additions & 2 deletions arch/arm/boot/dts/mt7623.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@
clock-names = "cpu", "intermediate";
operating-points-v2 = <&cpu_opp_table>;
#cooling-cells = <2>;
cooling-min-level = <0>;
cooling-max-level = <7>;
clock-frequency = <1300000000>;
};

Expand Down
11 changes: 10 additions & 1 deletion drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
unsigned long long ret;
int d_min, d_max;
bool wakeup = false;
bool has_sxd = false;
acpi_status status;

/*
Expand Down Expand Up @@ -581,6 +582,10 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
else
return -ENODATA;
}

if (status == AE_OK)
has_sxd = true;

d_min = ret;
wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid
&& adev->wakeup.sleep_state >= target_state;
Expand All @@ -599,7 +604,11 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
method[3] = 'W';
status = acpi_evaluate_integer(handle, method, NULL, &ret);
if (status == AE_NOT_FOUND) {
if (target_state > ACPI_STATE_S0)
/* No _SxW. In this case, the ACPI spec says that we
* must not go into any power state deeper than the
* value returned from _SxD.
*/
if (has_sxd && target_state > ACPI_STATE_S0)
d_max = d_min;
} else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) {
/* Fall back to D3cold if ret is not a valid state. */
Expand Down
24 changes: 9 additions & 15 deletions drivers/acpi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -849,23 +849,25 @@ static void lpi_check_constraints(void)
int i;

for (i = 0; i < lpi_constraints_table_size; ++i) {
acpi_handle handle = lpi_constraints_table[i].handle;
struct acpi_device *adev;

if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev))
if (!handle || acpi_bus_get_device(handle, &adev))
continue;

acpi_handle_debug(adev->handle,
acpi_handle_debug(handle,
"LPI: required min power state:%s current power state:%s\n",
acpi_power_state_string(lpi_constraints_table[i].min_dstate),
acpi_power_state_string(adev->power.state));

if (!adev->flags.power_manageable) {
acpi_handle_info(adev->handle, "LPI: Device not power manageble\n");
acpi_handle_info(handle, "LPI: Device not power manageable\n");
lpi_constraints_table[i].handle = NULL;
continue;
}

if (adev->power.state < lpi_constraints_table[i].min_dstate)
acpi_handle_info(adev->handle,
acpi_handle_info(handle,
"LPI: Constraint not met; min power state:%s current power state:%s\n",
acpi_power_state_string(lpi_constraints_table[i].min_dstate),
acpi_power_state_string(adev->power.state));
Expand Down Expand Up @@ -951,15 +953,8 @@ static int acpi_s2idle_prepare(void)
if (lps0_device_handle) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
} else {
/*
* The configuration of GPEs is changed here to avoid spurious
* wakeups, but that should not be necessary if this is a
* "low-power S0" platform and the low-power S0 _DSM is present.
*/
acpi_enable_all_wakeup_gpes();
acpi_os_wait_events_complete();
}

if (acpi_sci_irq_valid())
enable_irq_wake(acpi_sci_irq);

Expand Down Expand Up @@ -992,8 +987,9 @@ static void acpi_s2idle_sync(void)
* The EC driver uses the system workqueue and an additional special
* one, so those need to be flushed too.
*/
acpi_os_wait_events_complete(); /* synchronize SCI IRQ handling */
acpi_ec_flush_work();
acpi_os_wait_events_complete();
acpi_os_wait_events_complete(); /* synchronize Notify handling */
s2idle_wakeup = false;
}

Expand All @@ -1005,8 +1001,6 @@ static void acpi_s2idle_restore(void)
if (lps0_device_handle) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
} else {
acpi_enable_all_runtime_gpes();
}
}

Expand Down
25 changes: 17 additions & 8 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -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));

Expand All @@ -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));

Expand All @@ -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();
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions drivers/base/power/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 11 additions & 2 deletions drivers/base/power/wakeirq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand All @@ -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);

Expand Down
1 change: 1 addition & 0 deletions drivers/cpufreq/Kconfig.arm
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ config ARM_DT_BL_CPUFREQ
config ARM_SCPI_CPUFREQ
tristate "SCPI based CPUfreq driver"
depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
depends on !CPU_THERMAL || THERMAL
help
This adds the CPUfreq driver support for ARM platforms using SCPI
protocol for CPU power management.
Expand Down
Loading

0 comments on commit f2d2856

Please sign in to comment.