#include <linux/suspend.h>
#include <linux/reboot.h>
#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <asm/realmode.h>
+
#include "internal.h"
#include "sleep.h"
+u8 wake_sleep_flags = ACPI_NO_OPTIONAL_METHODS;
+static unsigned int gts, bfs;
+static int set_param_wake_flag(const char *val, struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+
+ if (ret)
+ return ret;
+
+ if (kp->arg == (const char *)>s) {
+ if (gts)
+ wake_sleep_flags |= ACPI_EXECUTE_GTS;
+ else
+ wake_sleep_flags &= ~ACPI_EXECUTE_GTS;
+ }
+ if (kp->arg == (const char *)&bfs) {
+ if (bfs)
+ wake_sleep_flags |= ACPI_EXECUTE_BFS;
+ else
+ wake_sleep_flags &= ~ACPI_EXECUTE_BFS;
+ }
+ return ret;
+}
+module_param_call(gts, set_param_wake_flag, param_get_int, >s, 0644);
+module_param_call(bfs, set_param_wake_flag, param_get_int, &bfs, 0644);
+MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
+MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
+
static u8 sleep_states[ACPI_S_STATE_COUNT];
static void acpi_sleep_tts_switch(u32 acpi_state)
static int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
+ unsigned long wakeup_pa = real_mode_header->wakeup_start;
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
- if (!acpi_wakeup_address) {
+ if (!wakeup_pa)
return -EFAULT;
- }
acpi_set_firmware_waking_vector(
- (acpi_physical_address)acpi_wakeup_address);
+ (acpi_physical_address)wakeup_pa);
}
ACPI_FLUSH_CPU_CACHE();
switch (acpi_state) {
case ACPI_STATE_S1:
barrier();
- status = acpi_enter_sleep_state(acpi_state);
+ status = acpi_enter_sleep_state(acpi_state, wake_sleep_flags);
break;
case ACPI_STATE_S3:
acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
/* Reprogram control registers and execute _BFS */
- acpi_leave_sleep_state_prep(acpi_state);
+ acpi_leave_sleep_state_prep(acpi_state, wake_sleep_flags);
/* ACPI 3.0 specs (P62) says that it's the responsibility
* of the OSPM to clear the status bit [ implying that the
ACPI_FLUSH_CPU_CACHE();
/* This shouldn't return. If it returns, we have a problem */
- status = acpi_enter_sleep_state(ACPI_STATE_S4);
+ status = acpi_enter_sleep_state(ACPI_STATE_S4, wake_sleep_flags);
/* Reprogram control registers and execute _BFS */
- acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+ acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags);
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
*/
acpi_enable();
/* Reprogram control registers and execute _BFS */
- acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+ acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags);
/* Check the hardware signature */
if (facs && s4_hardware_signature != facs->hardware_signature) {
printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
+/**
+ * acpi_pm_device_run_wake - Enable/disable wake-up for given device.
+ * @phys_dev: Device to enable/disable the platform to wake-up the system for.
+ * @enable: Whether enable or disable the wake-up functionality.
+ *
+ * Find the ACPI device object corresponding to @pci_dev and try to
+ * enable/disable the GPE associated with it.
+ */
+int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
+{
+ struct acpi_device *dev;
+ acpi_handle handle;
+
+ if (!device_run_wake(phys_dev))
+ return -EINVAL;
+
+ handle = DEVICE_ACPI_HANDLE(phys_dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) {
+ dev_dbg(phys_dev, "ACPI handle has no context in %s!\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (enable) {
+ acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
+ acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
+ } else {
+ acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
+ acpi_disable_wakeup_device_power(dev);
+ }
+
+ return 0;
+}
+
/**
* acpi_pm_device_sleep_wake - enable or disable the system wake-up
* capability of given device
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
printk(KERN_DEBUG "%s called\n", __func__);
local_irq_disable();
- acpi_enter_sleep_state(ACPI_STATE_S5);
+ acpi_enter_sleep_state(ACPI_STATE_S5, wake_sleep_flags);
}
/*
{
acpi_handle dummy;
- if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__GTS, &dummy)))
+ if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__GTS, &dummy)))
{
printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n");
printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, "
"please notify linux-acpi@vger.kernel.org\n");
}
- if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__BFS, &dummy)))
+ if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__BFS, &dummy)))
{
printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n");
printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, "