Commit ef05db16 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull more power management updates from Rafael Wysocki:
 "Additional power management updates.

  These fix a corner-case suspend-to-idle wakeup issue on systems where
  the ACPI SCI is shared with another wakeup source, add a kernel
  command line option to set pm_debug_messages via the kernel command
  line, add a document desctibing system-wide suspend and resume code
  flows, modify cpufreq Kconfig to choose schedutil as the preferred
  governor by default in a couple of cases and do some assorted
  cleanups.

  Specifics:

   - Fix corner-case suspend-to-idle wakeup issue on systems where the
     ACPI SCI is shared with another wakeup source (Hans de Goede).

   - Add document describing system-wide suspend and resume code flows
     to the admin guide (Rafael Wysocki).

   - Add kernel command line option to set pm_debug_messages (Chen Yu).

   - Choose schedutil as the preferred scaling governor by default on
     ARM big.LITTLE systems and on x86 systems using the intel_pstate
     driver in the passive mode (Linus Walleij, Rafael Wysocki).

   - Drop racy and redundant checks from the PM core's device_prepare()
     routine (Rafael Wysocki).

   - Make resume from hibernation take the hibernation_restore() return
     value into account (Dexuan Cui)"

* tag 'pm-5.7-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  platform/x86: intel_int0002_vgpio: Use acpi_register_wakeup_handler()
  ACPI: PM: Add acpi_[un]register_wakeup_handler()
  Documentation: PM: sleep: Document system-wide suspend code flows
  cpufreq: Select schedutil when using big.LITTLE
  PM: sleep: Add pm_debug_messages kernel command line option
  PM: sleep: core: Drop racy and redundant checks from device_prepare()
  PM: hibernate: Propagate the return value of hibernation_restore()
  cpufreq: intel_pstate: Select schedutil as the default governor
parents f183d269 54032b86
...@@ -3720,6 +3720,9 @@ ...@@ -3720,6 +3720,9 @@
Override pmtimer IOPort with a hex value. Override pmtimer IOPort with a hex value.
e.g. pmtmr=0x508 e.g. pmtmr=0x508
pm_debug_messages [SUSPEND,KNL]
Enable suspend/resume debug messages during boot up.
pnp.debug=1 [PNP] pnp.debug=1 [PNP]
Enable PNP debug messages (depends on the Enable PNP debug messages (depends on the
CONFIG_PNP_DEBUG_MESSAGES option). Change at run-time CONFIG_PNP_DEBUG_MESSAGES option). Change at run-time
......
This diff is collapsed.
...@@ -8,3 +8,4 @@ System-Wide Power Management ...@@ -8,3 +8,4 @@ System-Wide Power Management
:maxdepth: 2 :maxdepth: 2
sleep-states sleep-states
suspend-flows
...@@ -1009,6 +1009,10 @@ static bool acpi_s2idle_wake(void) ...@@ -1009,6 +1009,10 @@ static bool acpi_s2idle_wake(void)
if (acpi_any_fixed_event_status_set()) if (acpi_any_fixed_event_status_set())
return true; return true;
/* Check wakeups from drivers sharing the SCI. */
if (acpi_check_wakeup_handlers())
return true;
/* /*
* If the status bit is set for any enabled GPE other than the * If the status bit is set for any enabled GPE other than the
* EC one, the wakeup is regarded as a genuine one. * EC one, the wakeup is regarded as a genuine one.
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
extern void acpi_enable_wakeup_devices(u8 sleep_state); extern void acpi_enable_wakeup_devices(u8 sleep_state);
extern void acpi_disable_wakeup_devices(u8 sleep_state); extern void acpi_disable_wakeup_devices(u8 sleep_state);
extern bool acpi_check_wakeup_handlers(void);
extern struct list_head acpi_wakeup_device_list; extern struct list_head acpi_wakeup_device_list;
extern struct mutex acpi_device_lock; extern struct mutex acpi_device_lock;
......
...@@ -12,6 +12,15 @@ ...@@ -12,6 +12,15 @@
#include "internal.h" #include "internal.h"
#include "sleep.h" #include "sleep.h"
struct acpi_wakeup_handler {
struct list_head list_node;
bool (*wakeup)(void *context);
void *context;
};
static LIST_HEAD(acpi_wakeup_handler_head);
static DEFINE_MUTEX(acpi_wakeup_handler_mutex);
/* /*
* We didn't lock acpi_device_lock in the file, because it invokes oops in * We didn't lock acpi_device_lock in the file, because it invokes oops in
* suspend/resume and isn't really required as this is called in S-state. At * suspend/resume and isn't really required as this is called in S-state. At
...@@ -90,3 +99,75 @@ int __init acpi_wakeup_device_init(void) ...@@ -90,3 +99,75 @@ int __init acpi_wakeup_device_init(void)
mutex_unlock(&acpi_device_lock); mutex_unlock(&acpi_device_lock);
return 0; return 0;
} }
/**
* acpi_register_wakeup_handler - Register wakeup handler
* @wake_irq: The IRQ through which the device may receive wakeups
* @wakeup: Wakeup-handler to call when the SCI has triggered a wakeup
* @context: Context to pass to the handler when calling it
*
* Drivers which may share an IRQ with the SCI can use this to register
* a handler which returns true when the device they are managing wants
* to trigger a wakeup.
*/
int acpi_register_wakeup_handler(int wake_irq, bool (*wakeup)(void *context),
void *context)
{
struct acpi_wakeup_handler *handler;
/*
* If the device is not sharing its IRQ with the SCI, there is no
* need to register the handler.
*/
if (!acpi_sci_irq_valid() || wake_irq != acpi_sci_irq)
return 0;
handler = kmalloc(sizeof(*handler), GFP_KERNEL);
if (!handler)
return -ENOMEM;
handler->wakeup = wakeup;
handler->context = context;
mutex_lock(&acpi_wakeup_handler_mutex);
list_add(&handler->list_node, &acpi_wakeup_handler_head);
mutex_unlock(&acpi_wakeup_handler_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(acpi_register_wakeup_handler);
/**
* acpi_unregister_wakeup_handler - Unregister wakeup handler
* @wakeup: Wakeup-handler passed to acpi_register_wakeup_handler()
* @context: Context passed to acpi_register_wakeup_handler()
*/
void acpi_unregister_wakeup_handler(bool (*wakeup)(void *context),
void *context)
{
struct acpi_wakeup_handler *handler;
mutex_lock(&acpi_wakeup_handler_mutex);
list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
if (handler->wakeup == wakeup && handler->context == context) {
list_del(&handler->list_node);
kfree(handler);
break;
}
}
mutex_unlock(&acpi_wakeup_handler_mutex);
}
EXPORT_SYMBOL_GPL(acpi_unregister_wakeup_handler);
bool acpi_check_wakeup_handlers(void)
{
struct acpi_wakeup_handler *handler;
/* No need to lock, nothing else is running when we're called. */
list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
if (handler->wakeup(handler->context))
return true;
}
return false;
}
...@@ -1922,10 +1922,6 @@ static int device_prepare(struct device *dev, pm_message_t state) ...@@ -1922,10 +1922,6 @@ static int device_prepare(struct device *dev, pm_message_t state)
if (dev->power.syscore) if (dev->power.syscore)
return 0; return 0;
WARN_ON(!pm_runtime_enabled(dev) &&
dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
DPM_FLAG_LEAVE_SUSPENDED));
/* /*
* If a device's parent goes into runtime suspend at the wrong time, * If a device's parent goes into runtime suspend at the wrong time,
* it won't be possible to resume the device. To prevent this we * it won't be possible to resume the device. To prevent this we
...@@ -1973,8 +1969,7 @@ static int device_prepare(struct device *dev, pm_message_t state) ...@@ -1973,8 +1969,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
*/ */
spin_lock_irq(&dev->power.lock); spin_lock_irq(&dev->power.lock);
dev->power.direct_complete = state.event == PM_EVENT_SUSPEND && dev->power.direct_complete = state.event == PM_EVENT_SUSPEND &&
((pm_runtime_suspended(dev) && ret > 0) || (ret > 0 || dev->power.no_pm_callbacks) &&
dev->power.no_pm_callbacks) &&
!dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP); !dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP);
spin_unlock_irq(&dev->power.lock); spin_unlock_irq(&dev->power.lock);
return 0; return 0;
......
...@@ -37,10 +37,12 @@ config CPU_FREQ_STAT ...@@ -37,10 +37,12 @@ config CPU_FREQ_STAT
choice choice
prompt "Default CPUFreq governor" prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
default CPU_FREQ_DEFAULT_GOV_SCHEDUTIL if BIG_LITTLE
default CPU_FREQ_DEFAULT_GOV_SCHEDUTIL if X86_INTEL_PSTATE && SMP
default CPU_FREQ_DEFAULT_GOV_PERFORMANCE default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
help help
This option sets which CPUFreq governor shall be loaded at This option sets which CPUFreq governor shall be loaded at
startup. If in doubt, select 'performance'. startup. If in doubt, use the default setting.
config CPU_FREQ_DEFAULT_GOV_PERFORMANCE config CPU_FREQ_DEFAULT_GOV_PERFORMANCE
bool "performance" bool "performance"
......
...@@ -8,6 +8,8 @@ config X86_INTEL_PSTATE ...@@ -8,6 +8,8 @@ config X86_INTEL_PSTATE
depends on X86 depends on X86
select ACPI_PROCESSOR if ACPI select ACPI_PROCESSOR if ACPI
select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
select CPU_FREQ_GOV_PERFORMANCE
select CPU_FREQ_GOV_SCHEDUTIL if SMP
help help
This driver provides a P state for Intel core processors. This driver provides a P state for Intel core processors.
The driver implements an internal governor and will become The driver implements an internal governor and will become
......
...@@ -127,6 +127,14 @@ static irqreturn_t int0002_irq(int irq, void *data) ...@@ -127,6 +127,14 @@ static irqreturn_t int0002_irq(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static bool int0002_check_wake(void *data)
{
u32 gpe_sts_reg;
gpe_sts_reg = inl(GPE0A_STS_PORT);
return (gpe_sts_reg & GPE0A_PME_B0_STS_BIT);
}
static struct irq_chip int0002_byt_irqchip = { static struct irq_chip int0002_byt_irqchip = {
.name = DRV_NAME, .name = DRV_NAME,
.irq_ack = int0002_irq_ack, .irq_ack = int0002_irq_ack,
...@@ -220,6 +228,7 @@ static int int0002_probe(struct platform_device *pdev) ...@@ -220,6 +228,7 @@ static int int0002_probe(struct platform_device *pdev)
return ret; return ret;
} }
acpi_register_wakeup_handler(irq, int0002_check_wake, NULL);
device_init_wakeup(dev, true); device_init_wakeup(dev, true);
return 0; return 0;
} }
...@@ -227,6 +236,7 @@ static int int0002_probe(struct platform_device *pdev) ...@@ -227,6 +236,7 @@ static int int0002_probe(struct platform_device *pdev)
static int int0002_remove(struct platform_device *pdev) static int int0002_remove(struct platform_device *pdev)
{ {
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
acpi_unregister_wakeup_handler(int0002_check_wake, NULL);
return 0; return 0;
} }
......
...@@ -488,6 +488,11 @@ void __init acpi_nvs_nosave_s3(void); ...@@ -488,6 +488,11 @@ void __init acpi_nvs_nosave_s3(void);
void __init acpi_sleep_no_blacklist(void); void __init acpi_sleep_no_blacklist(void);
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
int acpi_register_wakeup_handler(
int wake_irq, bool (*wakeup)(void *context), void *context);
void acpi_unregister_wakeup_handler(
bool (*wakeup)(void *context), void *context);
struct acpi_osc_context { struct acpi_osc_context {
char *uuid_str; /* UUID string */ char *uuid_str; /* UUID string */
int rev; int rev;
......
...@@ -678,7 +678,7 @@ static int load_image_and_restore(void) ...@@ -678,7 +678,7 @@ static int load_image_and_restore(void)
error = swsusp_read(&flags); error = swsusp_read(&flags);
swsusp_close(FMODE_READ); swsusp_close(FMODE_READ);
if (!error) if (!error)
hibernation_restore(flags & SF_PLATFORM_MODE); error = hibernation_restore(flags & SF_PLATFORM_MODE);
pr_err("Failed to load image, recovering.\n"); pr_err("Failed to load image, recovering.\n");
swsusp_free(); swsusp_free();
......
...@@ -535,6 +535,13 @@ static ssize_t pm_debug_messages_store(struct kobject *kobj, ...@@ -535,6 +535,13 @@ static ssize_t pm_debug_messages_store(struct kobject *kobj,
power_attr(pm_debug_messages); power_attr(pm_debug_messages);
static int __init pm_debug_messages_setup(char *str)
{
pm_debug_messages_on = true;
return 1;
}
__setup("pm_debug_messages", pm_debug_messages_setup);
/** /**
* __pm_pr_dbg - Print a suspend debug message to the kernel log. * __pm_pr_dbg - Print a suspend debug message to the kernel log.
* @defer: Whether or not to use printk_deferred() to print the message. * @defer: Whether or not to use printk_deferred() to print the message.
......
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