Commit dfec4a84 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pm-4.19-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more power management updates from Rafael Wysocki:
 "These fix the main idle loop and the menu cpuidle governor, clean up
  the latter, fix a mistake in the PCI bus type's support for system
  suspend and resume, fix the ondemand and conservative cpufreq
  governors, address a build issue in the system wakeup framework and
  make the ACPI C-states desciptions less confusing.

  Specifics:

   - Make the idle loop handle stopped scheduler tick correctly (Rafael
     Wysocki).

   - Prevent the menu cpuidle governor from letting CPUs spend too much
     time in shallow idle states when it is invoked with scheduler tick
     stopped and clean it up somewhat (Rafael Wysocki).

   - Avoid invoking the platform firmware to make the platform enter the
     ACPI S3 sleep state with suspended PCIe root ports which may
     confuse the firmware and cause it to crash (Rafael Wysocki).

   - Fix sysfs-related race in the ondemand and conservative cpufreq
     governors which may cause the system to crash if the governor
     module is removed during an update of CPU frequency limits (Henry
     Willard).

   - Select SRCU when building the system wakeup framework to avoid a
     build issue in it (zhangyi).

   - Make the descriptions of ACPI C-states vendor-neutral to avoid
     confusion (Prarit Bhargava)"

* tag 'pm-4.19-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  cpuidle: menu: Handle stopped tick more aggressively
  sched: idle: Avoid retaining the tick when it has been stopped
  PCI / ACPI / PM: Resume all bridges on suspend-to-RAM
  cpuidle: menu: Update stale polling override comment
  cpufreq: governor: Avoid accessing invalid governor_data
  x86/ACPI/cstate: Make APCI C1 FFH MWAIT C-state description vendor-neutral
  cpuidle: menu: Fix white space
  PM / sleep: wakeup: Fix build error caused by missing SRCU support
parents 159127ea 01ac7c4c
...@@ -108,7 +108,7 @@ static long acpi_processor_ffh_cstate_probe_cpu(void *_cx) ...@@ -108,7 +108,7 @@ static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
cx->type); cx->type);
} }
snprintf(cx->desc, snprintf(cx->desc,
ACPI_CX_DESC_LEN, "ACPI FFH INTEL MWAIT 0x%x", ACPI_CX_DESC_LEN, "ACPI FFH MWAIT 0x%x",
cx->address); cx->address);
out: out:
return retval; return retval;
......
...@@ -555,12 +555,20 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop); ...@@ -555,12 +555,20 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
{ {
struct policy_dbs_info *policy_dbs = policy->governor_data; struct policy_dbs_info *policy_dbs;
/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
mutex_lock(&gov_dbs_data_mutex);
policy_dbs = policy->governor_data;
if (!policy_dbs)
goto out;
mutex_lock(&policy_dbs->update_mutex); mutex_lock(&policy_dbs->update_mutex);
cpufreq_policy_apply_limits(policy); cpufreq_policy_apply_limits(policy);
gov_update_sample_delay(policy_dbs, 0); gov_update_sample_delay(policy_dbs, 0);
mutex_unlock(&policy_dbs->update_mutex); mutex_unlock(&policy_dbs->update_mutex);
out:
mutex_unlock(&gov_dbs_data_mutex);
} }
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits); EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits);
...@@ -328,9 +328,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -328,9 +328,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
unsigned int polling_threshold; unsigned int polling_threshold;
/* /*
* We want to default to C1 (hlt), not to busy polling * Default to a physical idle state, not to busy polling, unless
* unless the timer is happening really really soon, or * a timer is going to trigger really really soon.
* C1's exit latency exceeds the user configured limit.
*/ */
polling_threshold = max_t(unsigned int, 20, s->target_residency); polling_threshold = max_t(unsigned int, 20, s->target_residency);
if (data->next_timer_us > polling_threshold && if (data->next_timer_us > polling_threshold &&
...@@ -349,14 +348,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -349,14 +348,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* If the tick is already stopped, the cost of possible short * If the tick is already stopped, the cost of possible short
* idle duration misprediction is much higher, because the CPU * idle duration misprediction is much higher, because the CPU
* may be stuck in a shallow idle state for a long time as a * may be stuck in a shallow idle state for a long time as a
* result of it. In that case say we might mispredict and try * result of it. In that case say we might mispredict and use
* to force the CPU into a state for which we would have stopped * the known time till the closest timer event for the idle
* the tick, unless a timer is going to expire really soon * state selection.
* anyway.
*/ */
if (data->predicted_us < TICK_USEC) if (data->predicted_us < TICK_USEC)
data->predicted_us = min_t(unsigned int, TICK_USEC, data->predicted_us = ktime_to_us(delta_next);
ktime_to_us(delta_next));
} else { } else {
/* /*
* Use the performance multiplier and the user-configurable * Use the performance multiplier and the user-configurable
...@@ -381,8 +378,22 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -381,8 +378,22 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
continue; continue;
if (idx == -1) if (idx == -1)
idx = i; /* first enabled state */ idx = i; /* first enabled state */
if (s->target_residency > data->predicted_us) if (s->target_residency > data->predicted_us) {
break; if (!tick_nohz_tick_stopped())
break;
/*
* If the state selected so far is shallow and this
* state's target residency matches the time till the
* closest timer event, select this one to avoid getting
* stuck in the shallow one for too long.
*/
if (drv->states[idx].target_residency < TICK_USEC &&
s->target_residency <= ktime_to_us(delta_next))
idx = i;
goto out;
}
if (s->exit_latency > latency_req) { if (s->exit_latency > latency_req) {
/* /*
* If we break out of the loop for latency reasons, use * If we break out of the loop for latency reasons, use
...@@ -403,14 +414,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -403,14 +414,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* Don't stop the tick if the selected state is a polling one or if the * Don't stop the tick if the selected state is a polling one or if the
* expected idle duration is shorter than the tick period length. * expected idle duration is shorter than the tick period length.
*/ */
if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) ||
expected_interval < TICK_USEC) { expected_interval < TICK_USEC) && !tick_nohz_tick_stopped()) {
unsigned int delta_next_us = ktime_to_us(delta_next); unsigned int delta_next_us = ktime_to_us(delta_next);
*stop_tick = false; *stop_tick = false;
if (!tick_nohz_tick_stopped() && idx > 0 && if (idx > 0 && drv->states[idx].target_residency > delta_next_us) {
drv->states[idx].target_residency > delta_next_us) {
/* /*
* The tick is not going to be stopped and the target * The tick is not going to be stopped and the target
* residency of the state to be returned is not within * residency of the state to be returned is not within
...@@ -418,8 +428,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -418,8 +428,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* tick, so try to correct that. * tick, so try to correct that.
*/ */
for (i = idx - 1; i >= 0; i--) { for (i = idx - 1; i >= 0; i--) {
if (drv->states[i].disabled || if (drv->states[i].disabled ||
dev->states_usage[i].disable) dev->states_usage[i].disable)
continue; continue;
idx = i; idx = i;
...@@ -429,6 +439,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -429,6 +439,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
} }
} }
out:
data->last_state_idx = idx; data->last_state_idx = idx;
return data->last_state_idx; return data->last_state_idx;
......
...@@ -615,13 +615,11 @@ static bool acpi_pci_need_resume(struct pci_dev *dev) ...@@ -615,13 +615,11 @@ static bool acpi_pci_need_resume(struct pci_dev *dev)
/* /*
* In some cases (eg. Samsung 305V4A) leaving a bridge in suspend over * In some cases (eg. Samsung 305V4A) leaving a bridge in suspend over
* system-wide suspend/resume confuses the platform firmware, so avoid * system-wide suspend/resume confuses the platform firmware, so avoid
* doing that, unless the bridge has a driver that should take care of * doing that. According to Section 16.1.6 of ACPI 6.2, endpoint
* the PM handling. According to Section 16.1.6 of ACPI 6.2, endpoint
* devices are expected to be in D3 before invoking the S3 entry path * devices are expected to be in D3 before invoking the S3 entry path
* from the firmware, so they should not be affected by this issue. * from the firmware, so they should not be affected by this issue.
*/ */
if (pci_is_bridge(dev) && !dev->driver && if (pci_is_bridge(dev) && acpi_target_system_state() != ACPI_STATE_S0)
acpi_target_system_state() != ACPI_STATE_S0)
return true; return true;
if (!adev || !acpi_device_power_manageable(adev)) if (!adev || !acpi_device_power_manageable(adev))
......
...@@ -105,6 +105,7 @@ config PM_SLEEP ...@@ -105,6 +105,7 @@ config PM_SLEEP
def_bool y def_bool y
depends on SUSPEND || HIBERNATE_CALLBACKS depends on SUSPEND || HIBERNATE_CALLBACKS
select PM select PM
select SRCU
config PM_SLEEP_SMP config PM_SLEEP_SMP
def_bool y def_bool y
......
...@@ -190,7 +190,7 @@ static void cpuidle_idle_call(void) ...@@ -190,7 +190,7 @@ static void cpuidle_idle_call(void)
*/ */
next_state = cpuidle_select(drv, dev, &stop_tick); next_state = cpuidle_select(drv, dev, &stop_tick);
if (stop_tick) if (stop_tick || tick_nohz_tick_stopped())
tick_nohz_idle_stop_tick(); tick_nohz_idle_stop_tick();
else else
tick_nohz_idle_retain_tick(); tick_nohz_idle_retain_tick();
......
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