summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_pad.c2
-rw-r--r--drivers/acpi/acpica/evxfevnt.c19
-rw-r--r--drivers/acpi/battery.c8
-rw-r--r--drivers/acpi/blacklist.c2
-rw-r--r--drivers/acpi/ec.c107
-rw-r--r--drivers/acpi/ec_sys.c160
-rw-r--r--drivers/acpi/internal.h24
-rw-r--r--drivers/acpi/osl.c40
-rw-r--r--drivers/acpi/pci_root.c9
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_idle.c14
-rw-r--r--drivers/acpi/sleep.c35
14 files changed, 286 insertions, 155 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 74641151880..08e0140920e 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -104,6 +104,24 @@ config ACPI_SYSFS_POWER
help
Say N to disable power /sys interface
+config ACPI_EC_DEBUGFS
+ tristate "EC read/write access through /sys/kernel/debug/ec"
+ default n
+ help
+ Say N to disable Embedded Controller /sys/kernel/debug interface
+
+ Be aware that using this interface can confuse your Embedded
+ Controller in a way that a normal reboot is not enough. You then
+ have to power of your system, and remove the laptop battery for
+ some seconds.
+ An Embedded Controller typically is available on laptops and reads
+ sensor values like battery state and temperature.
+ The kernel accesses the EC through ACPI parsed code provided by BIOS
+ tables. This option allows to access the EC directly without ACPI
+ code being involved.
+ Thus this option is a debug option that helps to write ACPI drivers
+ and can be used to identify ACPI code or EC firmware bugs.
+
config ACPI_PROC_EVENT
bool "Deprecated /proc/acpi/event support"
depends on PROC_FS
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 6ee33169e1d..833b582d176 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
obj-$(CONFIG_ACPI_HED) += hed.o
+obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
# processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 446aced33af..b76848c80be 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -77,7 +77,7 @@ static void power_saving_mwait_init(void)
power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
(highest_subcstate - 1);
-#if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86)
+#if defined(CONFIG_X86)
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 53d591a1113..0ec900da579 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -70,6 +70,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
acpi_status acpi_enable(void)
{
acpi_status status;
+ int retry;
ACPI_FUNCTION_TRACE(acpi_enable);
@@ -98,16 +99,18 @@ acpi_status acpi_enable(void)
/* Sanity check that transition succeeded */
- if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) {
- ACPI_ERROR((AE_INFO,
- "Hardware did not enter ACPI mode"));
- return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
+ for (retry = 0; retry < 30000; ++retry) {
+ if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
+ if (retry != 0)
+ ACPI_WARNING((AE_INFO,
+ "Platform took > %d00 usec to enter ACPI mode", retry));
+ return_ACPI_STATUS(AE_OK);
+ }
+ acpi_os_stall(100); /* 100 usec */
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "Transition to ACPI mode successful\n"));
-
- return_ACPI_STATUS(AE_OK);
+ ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode"));
+ return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
}
ACPI_EXPORT_SYMBOL(acpi_enable)
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 3026e3fa83e..dc58402b0a1 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -868,9 +868,15 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
static void acpi_battery_notify(struct acpi_device *device, u32 event)
{
struct acpi_battery *battery = acpi_driver_data(device);
+#ifdef CONFIG_ACPI_SYSFS_POWER
+ struct device *old;
+#endif
if (!battery)
return;
+#ifdef CONFIG_ACPI_SYSFS_POWER
+ old = battery->bat.dev;
+#endif
acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery));
@@ -879,7 +885,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
acpi_battery_present(battery));
#ifdef CONFIG_ACPI_SYSFS_POWER
/* acpi_battery_update could remove power_supply object */
- if (battery->bat.dev)
+ if (old && battery->bat.dev)
power_supply_changed(&battery->bat);
#endif
}
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 01381be05e9..2bb28b9d91c 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -214,7 +214,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
.ident = "Sony VGN-SR290J",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"),
},
},
{
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1e6d4184f0e..f31291ba94d 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,8 +34,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -45,10 +43,13 @@
#include <acpi/acpi_drivers.h>
#include <linux/dmi.h>
+#include "internal.h"
+
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
+#undef PREFIX
#define PREFIX "ACPI: EC: "
/* EC status register */
@@ -106,19 +107,8 @@ struct transaction {
bool done;
};
-static struct acpi_ec {
- acpi_handle handle;
- unsigned long gpe;
- unsigned long command_addr;
- unsigned long data_addr;
- unsigned long global_lock;
- unsigned long flags;
- struct mutex lock;
- wait_queue_head_t wait;
- struct list_head list;
- struct transaction *curr;
- spinlock_t curr_lock;
-} *boot_ec, *first_ec;
+struct acpi_ec *boot_ec, *first_ec;
+EXPORT_SYMBOL(first_ec);
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
@@ -672,72 +662,6 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
}
/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-
-static struct proc_dir_entry *acpi_ec_dir;
-
-static int acpi_ec_read_info(struct seq_file *seq, void *offset)
-{
- struct acpi_ec *ec = seq->private;
-
- if (!ec)
- goto end;
-
- seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
- seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
- (unsigned)ec->command_addr, (unsigned)ec->data_addr);
- seq_printf(seq, "use global lock:\t%s\n",
- ec->global_lock ? "yes" : "no");
- end:
- return 0;
-}
-
-static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_ec_read_info, PDE(inode)->data);
-}
-
-static const struct file_operations acpi_ec_info_ops = {
- .open = acpi_ec_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int acpi_ec_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_ec_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO,
- acpi_device_dir(device),
- &acpi_ec_info_ops, acpi_driver_data(device));
- if (!entry)
- return -ENODEV;
- return 0;
-}
-
-static int acpi_ec_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static acpi_status
@@ -887,7 +811,12 @@ static int acpi_ec_add(struct acpi_device *device)
if (!first_ec)
first_ec = ec;
device->driver_data = ec;
- acpi_ec_add_fs(device);
+
+ WARN(!request_region(ec->data_addr, 1, "EC data"),
+ "Could not request EC data io port 0x%lx", ec->data_addr);
+ WARN(!request_region(ec->command_addr, 1, "EC cmd"),
+ "Could not request EC cmd io port 0x%lx", ec->command_addr);
+
pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
@@ -914,7 +843,8 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
kfree(handler);
}
mutex_unlock(&ec->lock);
- acpi_ec_remove_fs(device);
+ release_region(ec->data_addr, 1);
+ release_region(ec->command_addr, 1);
device->driver_data = NULL;
if (ec == first_ec)
first_ec = NULL;
@@ -1095,16 +1025,10 @@ int __init acpi_ec_init(void)
{
int result = 0;
- acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
- if (!acpi_ec_dir)
- return -ENODEV;
-
/* Now register the driver for the EC */
result = acpi_bus_register_driver(&acpi_ec_driver);
- if (result < 0) {
- remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
+ if (result < 0)
return -ENODEV;
- }
return result;
}
@@ -1115,9 +1039,6 @@ static void __exit acpi_ec_exit(void)
{
acpi_bus_unregister_driver(&acpi_ec_driver);
-
- remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
-
return;
}
#endif /* 0 */
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
new file mode 100644
index 00000000000..0e869b3f81c
--- /dev/null
+++ b/drivers/acpi/ec_sys.c
@@ -0,0 +1,160 @@
+/*
+ * ec_sys.c
+ *
+ * Copyright (C) 2010 SUSE Products GmbH/Novell
+ * Author:
+ * Thomas Renninger <trenn@suse.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include "internal.h"
+
+MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
+MODULE_DESCRIPTION("ACPI EC sysfs access driver");
+MODULE_LICENSE("GPL");
+
+static bool write_support;
+module_param(write_support, bool, 0644);
+MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
+ "be needed.");
+
+#define EC_SPACE_SIZE 256
+
+struct sysdev_class acpi_ec_sysdev_class = {
+ .name = "ec",
+};
+
+static struct dentry *acpi_ec_debugfs_dir;
+
+static int acpi_ec_open_io(struct inode *i, struct file *f)
+{
+ f->private_data = i->i_private;
+ return 0;
+}
+
+static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
+ size_t count, loff_t *off)
+{
+ /* Use this if support reading/writing multiple ECs exists in ec.c:
+ * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
+ */
+ unsigned int size = EC_SPACE_SIZE;
+ u8 *data = (u8 *) buf;
+ loff_t init_off = *off;
+ int err = 0;
+
+ if (*off >= size)
+ return 0;
+ if (*off + count >= size) {
+ size -= *off;
+ count = size;
+ } else
+ size = count;
+
+ while (size) {
+ err = ec_read(*off, &data[*off - init_off]);
+ if (err)
+ return err;
+ *off += 1;
+ size--;
+ }
+ return count;
+}
+
+static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ /* Use this if support reading/writing multiple ECs exists in ec.c:
+ * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
+ */
+
+ unsigned int size = count;
+ loff_t init_off = *off;
+ u8 *data = (u8 *) buf;
+ int err = 0;
+
+ if (*off >= EC_SPACE_SIZE)
+ return 0;
+ if (*off + count >= EC_SPACE_SIZE) {
+ size = EC_SPACE_SIZE - *off;
+ count = size;
+ }
+
+ while (size) {
+ u8 byte_write = data[*off - init_off];
+ err = ec_write(*off, byte_write);
+ if (err)
+ return err;
+
+ *off += 1;
+ size--;
+ }
+ return count;
+}
+
+static struct file_operations acpi_ec_io_ops = {
+ .owner = THIS_MODULE,
+ .open = acpi_ec_open_io,
+ .read = acpi_ec_read_io,
+ .write = acpi_ec_write_io,
+};
+
+int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
+{
+ struct dentry *dev_dir;
+ char name[64];
+ mode_t mode = 0400;
+
+ if (ec_device_count == 0) {
+ acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL);
+ if (!acpi_ec_debugfs_dir)
+ return -ENOMEM;
+ }
+
+ sprintf(name, "ec%u", ec_device_count);
+ dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir);
+ if (!dev_dir) {
+ if (ec_device_count != 0)
+ goto error;
+ return -ENOMEM;
+ }
+
+ if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe))
+ goto error;
+ if (!debugfs_create_bool("use_global_lock", 0444, dev_dir,
+ (u32 *)&first_ec->global_lock))
+ goto error;
+
+ if (write_support)
+ mode = 0600;
+ if (!debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops))
+ goto error;
+
+ return 0;
+
+error:
+ debugfs_remove_recursive(acpi_ec_debugfs_dir);
+ return -ENOMEM;
+}
+
+static int __init acpi_ec_sys_init(void)
+{
+ int err = 0;
+ if (first_ec)
+ err = acpi_ec_add_debugfs(first_ec, 0);
+ else
+ err = -ENODEV;
+ return err;
+}
+
+static void __exit acpi_ec_sys_exit(void)
+{
+ debugfs_remove_recursive(acpi_ec_debugfs_dir);
+}
+
+module_init(acpi_ec_sys_init);
+module_exit(acpi_ec_sys_exit);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f8f190ec066..8ae27264a00 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -18,6 +18,11 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#ifndef _ACPI_INTERNAL_H_
+#define _ACPI_INTERNAL_H_
+
+#include <linux/sysdev.h>
+
#define PREFIX "ACPI: "
int init_acpi_device_notify(void);
@@ -46,6 +51,23 @@ void acpi_early_processor_set_pdc(void);
/* --------------------------------------------------------------------------
Embedded Controller
-------------------------------------------------------------------------- */
+struct acpi_ec {
+ acpi_handle handle;
+ unsigned long gpe;
+ unsigned long command_addr;
+ unsigned long data_addr;
+ unsigned long global_lock;
+ unsigned long flags;
+ struct mutex lock;
+ wait_queue_head_t wait;
+ struct list_head list;
+ struct transaction *curr;
+ spinlock_t curr_lock;
+ struct sys_device sysdev;
+};
+
+extern struct acpi_ec *first_ec;
+
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
@@ -63,3 +85,5 @@ int acpi_sleep_proc_init(void);
#else
static inline int acpi_sleep_proc_init(void) { return 0; }
#endif
+
+#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 44bddc5bc6a..f14d3f251d2 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -191,36 +191,11 @@ acpi_status __init acpi_os_initialize(void)
return AE_OK;
}
-static void bind_to_cpu0(struct work_struct *work)
-{
- set_cpus_allowed_ptr(current, cpumask_of(0));
- kfree(work);
-}
-
-static void bind_workqueue(struct workqueue_struct *wq)
-{
- struct work_struct *work;
-
- work = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
- INIT_WORK(work, bind_to_cpu0);
- queue_work(wq, work);
-}
-
acpi_status acpi_os_initialize1(void)
{
- /*
- * On some machines, a software-initiated SMI causes corruption unless
- * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
- * typically it's done in GPE-related methods that are run via
- * workqueues, so we can avoid the known corruption cases by binding
- * the workqueues to CPU 0.
- */
- kacpid_wq = create_singlethread_workqueue("kacpid");
- bind_workqueue(kacpid_wq);
- kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
- bind_workqueue(kacpi_notify_wq);
- kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
- bind_workqueue(kacpi_hotplug_wq);
+ kacpid_wq = create_workqueue("kacpid");
+ kacpi_notify_wq = create_workqueue("kacpi_notify");
+ kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);
@@ -766,7 +741,14 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
else
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- ret = queue_work(queue, &dpc->work);
+ /*
+ * On some machines, a software-initiated SMI causes corruption unless
+ * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
+ * typically it's done in GPE-related methods that are run via
+ * workqueues, so we can avoid the known corruption cases by always
+ * queueing on CPU 0.
+ */
+ ret = queue_work_on(0, queue, &dpc->work);
if (!ret) {
printk(KERN_ERR PREFIX
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4eac59393ed..1f67057af2a 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -33,6 +33,7 @@
#include <linux/pm_runtime.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
+#include <linux/pci-aspm.h>
#include <linux/acpi.h>
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
@@ -543,6 +544,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
+ status = acpi_pci_osc_control_set(root->device->handle,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n");
+ pcie_no_aspm();
+ }
+
pci_acpi_add_bus_pm_notifier(device, root->bus);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 51284351418..e9699aaed10 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -223,7 +223,7 @@ static bool processor_physically_present(acpi_handle handle)
type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
cpuid = acpi_get_cpuid(handle, type, acpi_id);
- if (cpuid == -1)
+ if ((cpuid == -1) && (num_possible_cpus() > 1))
return false;
return true;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index b1b385692f4..b4c2f3bdade 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -76,14 +76,19 @@ static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
module_param(max_cstate, uint, 0000);
static unsigned int nocst __read_mostly;
module_param(nocst, uint, 0000);
+static int bm_check_disable __read_mostly;
+module_param(bm_check_disable, uint, 0000);
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);
+#ifdef CONFIG_ACPI_PROCFS
static u64 us_to_pm_timer_ticks(s64 t)
{
return div64_u64(t * PM_TIMER_FREQUENCY, 1000000);
}
+#endif
+
/*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
* For now disable this. Probably a bug somewhere else.
@@ -159,7 +164,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr,
if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))
return;
- if (boot_cpu_has(X86_FEATURE_AMDC1E))
+ if (c1e_detected)
type = ACPI_STATE_C1;
/*
@@ -259,7 +264,7 @@ int acpi_processor_resume(struct acpi_device * device)
return 0;
}
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
+#if defined(CONFIG_X86)
static void tsc_check_state(int state)
{
switch (boot_cpu_data.x86_vendor) {
@@ -763,6 +768,9 @@ static int acpi_idle_bm_check(void)
{
u32 bm_status = 0;
+ if (bm_check_disable)
+ return 0;
+
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status)
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
@@ -947,7 +955,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (acpi_idle_suspend)
return(acpi_idle_enter_c1(dev, state));
- if (acpi_idle_bm_check()) {
+ if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
if (dev->safe_state) {
dev->last_state = dev->safe_state;
return dev->safe_state->enter(dev, dev->safe_state);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index aaa1af55e28..e143203254a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -82,6 +82,20 @@ static int acpi_sleep_prepare(u32 acpi_state)
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
/*
+ * The ACPI specification wants us to save NVS memory regions during hibernation
+ * and to restore them during the subsequent resume. Windows does that also for
+ * suspend to RAM. However, it is known that this mechanism does not work on
+ * all machines, so we allow the user to disable it with the help of the
+ * 'acpi_sleep=nonvs' kernel command line option.
+ */
+static bool nvs_nosave;
+
+void __init acpi_nvs_nosave(void)
+{
+ nvs_nosave = true;
+}
+
+/*
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
* user to request that behavior by using the 'acpi_old_suspend_ordering'
* kernel command line option that causes the following variable to be set.
@@ -197,8 +211,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
- error = suspend_nvs_alloc();
-
+ error = nvs_nosave ? 0 : suspend_nvs_alloc();
if (error)
return error;
@@ -388,20 +401,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
-/*
- * The ACPI specification wants us to save NVS memory regions during hibernation
- * and to restore them during the subsequent resume. However, it is not certain
- * if this mechanism is going to work on all machines, so we allow the user to
- * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
- * option.
- */
-static bool s4_no_nvs;
-
-void __init acpi_s4_no_nvs(void)
-{
- s4_no_nvs = true;
-}
-
static unsigned long s4_hardware_signature;
static struct acpi_table_facs *facs;
static bool nosigcheck;
@@ -415,7 +414,7 @@ static int acpi_hibernation_begin(void)
{
int error;
- error = s4_no_nvs ? 0 : suspend_nvs_alloc();
+ error = nvs_nosave ? 0 : suspend_nvs_alloc();
if (!error) {
acpi_target_sleep_state = ACPI_STATE_S4;
acpi_sleep_tts_switch(acpi_target_sleep_state);
@@ -510,7 +509,7 @@ static int acpi_hibernation_begin_old(void)
error = acpi_sleep_prepare(ACPI_STATE_S4);
if (!error) {
- if (!s4_no_nvs)
+ if (!nvs_nosave)
error = suspend_nvs_alloc();
if (!error)
acpi_target_sleep_state = ACPI_STATE_S4;