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
This commit is contained in:
@@ -1009,6 +1009,10 @@ static bool acpi_s2idle_wake(void)
|
||||
if (acpi_any_fixed_event_status_set())
|
||||
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
|
||||
* EC one, the wakeup is regarded as a genuine one.
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
extern void acpi_enable_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 mutex acpi_device_lock;
|
||||
|
@@ -12,6 +12,15 @@
|
||||
#include "internal.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
|
||||
* 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)
|
||||
mutex_unlock(&acpi_device_lock);
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user