aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/thinkpad-acpi.txt73
-rw-r--r--arch/x86/kernel/acpi/processor.c3
-rw-r--r--arch/x86/kernel/acpi/sleep_64.c3
-rw-r--r--arch/x86/kernel/io_apic_32.c21
-rw-r--r--arch/x86/kernel/io_apic_64.c24
-rw-r--r--arch/x86/pci/acpi.c2
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/ac.c20
-rw-r--r--drivers/acpi/battery.c22
-rw-r--r--drivers/acpi/ec.c100
-rw-r--r--drivers/acpi/osl.c25
-rw-r--r--drivers/acpi/processor_core.c19
-rw-r--r--drivers/acpi/processor_idle.c111
-rw-r--r--drivers/acpi/processor_throttling.c286
-rw-r--r--drivers/acpi/sbs.c43
-rw-r--r--drivers/acpi/tables/tbutils.c2
-rw-r--r--drivers/acpi/video.c155
-rw-r--r--drivers/misc/thinkpad_acpi.c231
-rw-r--r--drivers/misc/thinkpad_acpi.h4
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c24
-rw-r--r--include/acpi/processor.h1
-rw-r--r--include/linux/acpi.h5
-rw-r--r--include/linux/cpuidle.h1
24 files changed, 813 insertions, 382 deletions
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index ec499265dec..10c041ca13c 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,7 +1,7 @@
ThinkPad ACPI Extras Driver
- Version 0.16
- August 2nd, 2007
+ Version 0.17
+ October 04th, 2007
Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -923,19 +923,34 @@ sysfs backlight device "thinkpad_screen"
This feature allows software control of the LCD brightness on ThinkPad
models which don't have a hardware brightness slider.
-It has some limitations: the LCD backlight cannot be actually turned on or off
-by this interface, and in many ThinkPad models, the "dim while on battery"
-functionality will be enabled by the BIOS when this interface is used, and
-cannot be controlled.
-
-The backlight control has eight levels, ranging from 0 to 7. Some of the
-levels may not be distinct.
-
-There are two interfaces to the firmware for brightness control, EC and CMOS.
-To select which one should be used, use the brightness_mode module parameter:
-brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
-brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect
-which interface to use.
+It has some limitations: the LCD backlight cannot be actually turned on or
+off by this interface, and in many ThinkPad models, the "dim while on
+battery" functionality will be enabled by the BIOS when this interface is
+used, and cannot be controlled.
+
+On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
+has eight brightness levels, ranging from 0 to 7. Some of the levels
+may not be distinct. Later Lenovo models that implement the ACPI
+display backlight brightness control methods have 16 levels, ranging
+from 0 to 15.
+
+There are two interfaces to the firmware for direct brightness control,
+EC and CMOS. To select which one should be used, use the
+brightness_mode module parameter: brightness_mode=1 selects EC mode,
+brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
+and CMOS. The driver tries to autodetect which interface to use.
+
+When display backlight brightness controls are available through the
+standard ACPI interface, it is best to use it instead of this direct
+ThinkPad-specific interface. The driver will disable its native
+backlight brightness control interface if it detects that the standard
+ACPI interface is available in the ThinkPad.
+
+The brightness_enable module parameter can be used to control whether
+the LCD brightness control feature will be enabled when available.
+brightness_enable=0 forces it to be disabled. brightness_enable=1
+forces it to be enabled when available, even if the standard ACPI
+interface is also available.
Procfs notes:
@@ -947,11 +962,11 @@ Procfs notes:
Sysfs notes:
-The interface is implemented through the backlight sysfs class, which is poorly
-documented at this time.
+The interface is implemented through the backlight sysfs class, which is
+poorly documented at this time.
-Locate the thinkpad_screen device under /sys/class/backlight, and inside it
-there will be the following attributes:
+Locate the thinkpad_screen device under /sys/class/backlight, and inside
+it there will be the following attributes:
max_brightness:
Reads the maximum brightness the hardware can be set to.
@@ -961,17 +976,19 @@ there will be the following attributes:
Reads what brightness the screen is set to at this instant.
brightness:
- Writes request the driver to change brightness to the given
- value. Reads will tell you what brightness the driver is trying
- to set the display to when "power" is set to zero and the display
- has not been dimmed by a kernel power management event.
+ Writes request the driver to change brightness to the
+ given value. Reads will tell you what brightness the
+ driver is trying to set the display to when "power" is set
+ to zero and the display has not been dimmed by a kernel
+ power management event.
power:
- power management mode, where 0 is "display on", and 1 to 3 will
- dim the display backlight to brightness level 0 because
- thinkpad-acpi cannot really turn the backlight off. Kernel
- power management events can temporarily increase the current
- power management level, i.e. they can dim the display.
+ power management mode, where 0 is "display on", and 1 to 3
+ will dim the display backlight to brightness level 0
+ because thinkpad-acpi cannot really turn the backlight
+ off. Kernel power management events can temporarily
+ increase the current power management level, i.e. they can
+ dim the display.
Volume control -- /proc/acpi/ibm/volume
diff --git a/arch/x86/kernel/acpi/processor.c b/arch/x86/kernel/acpi/processor.c
index f63e5ff0aca..a25db514c71 100644
--- a/arch/x86/kernel/acpi/processor.c
+++ b/arch/x86/kernel/acpi/processor.c
@@ -49,6 +49,9 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
if (cpu_has(c, X86_FEATURE_EST))
buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;
+ if (cpu_has(c, X86_FEATURE_ACPI))
+ buf[2] |= ACPI_PDC_T_FFH;
+
obj->type = ACPI_TYPE_BUFFER;
obj->buffer.length = 12;
obj->buffer.pointer = (u8 *) buf;
diff --git a/arch/x86/kernel/acpi/sleep_64.c b/arch/x86/kernel/acpi/sleep_64.c
index 79475d23707..da42de261ba 100644
--- a/arch/x86/kernel/acpi/sleep_64.c
+++ b/arch/x86/kernel/acpi/sleep_64.c
@@ -115,6 +115,3 @@ static int __init acpi_sleep_setup(char *str)
__setup("acpi_sleep=", acpi_sleep_setup);
-void acpi_pci_link_exit(void)
-{
-}
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c
index f35c6eb33da..6bb80ea5f4e 100644
--- a/arch/x86/kernel/io_apic_32.c
+++ b/arch/x86/kernel/io_apic_32.c
@@ -962,7 +962,7 @@ static int EISA_ELCR(unsigned int irq)
#define default_MCA_trigger(idx) (1)
#define default_MCA_polarity(idx) (0)
-static int __init MPBIOS_polarity(int idx)
+static int MPBIOS_polarity(int idx)
{
int bus = mp_irqs[idx].mpc_srcbus;
int polarity;
@@ -2830,6 +2830,25 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
return 0;
}
+int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
+{
+ int i;
+
+ if (skip_ioapic_setup)
+ return -1;
+
+ for (i = 0; i < mp_irq_entries; i++)
+ if (mp_irqs[i].mpc_irqtype == mp_INT &&
+ mp_irqs[i].mpc_srcbusirq == bus_irq)
+ break;
+ if (i >= mp_irq_entries)
+ return -1;
+
+ *trigger = irq_trigger(i);
+ *polarity = irq_polarity(i);
+ return 0;
+}
+
#endif /* CONFIG_ACPI */
static int __init parse_disable_timer_pin_1(char *arg)
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index 953328b55a3..435a8c9b55f 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -546,7 +546,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
#define default_PCI_trigger(idx) (1)
#define default_PCI_polarity(idx) (1)
-static int __init MPBIOS_polarity(int idx)
+static int MPBIOS_polarity(int idx)
{
int bus = mp_irqs[idx].mpc_srcbus;
int polarity;
@@ -2222,8 +2222,27 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
return 0;
}
-#endif /* CONFIG_ACPI */
+int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
+{
+ int i;
+
+ if (skip_ioapic_setup)
+ return -1;
+
+ for (i = 0; i < mp_irq_entries; i++)
+ if (mp_irqs[i].mpc_irqtype == mp_INT &&
+ mp_irqs[i].mpc_srcbusirq == bus_irq)
+ break;
+ if (i >= mp_irq_entries)
+ return -1;
+
+ *trigger = irq_trigger(i);
+ *polarity = irq_polarity(i);
+ return 0;
+}
+
+#endif /* CONFIG_ACPI */
/*
* This function currently is only a helper for the i386 smp boot process where
@@ -2260,3 +2279,4 @@ void __init setup_ioapic_dest(void)
}
}
#endif
+
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 7e35078673a..0234f2831bf 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -13,7 +13,7 @@ static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
return 0;
}
-static struct dmi_system_id acpi_pciprobe_dmi_table[] = {
+static struct dmi_system_id acpi_pciprobe_dmi_table[] __devinitdata = {
/*
* Systems where PCI IO resource ISA alignment can be skipped
* when the ISA enable bit in the bridge control is not set
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 087a7028ae8..b9f923ef173 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -50,7 +50,6 @@ config ACPI_SLEEP
config ACPI_PROCFS
bool "Deprecated /proc/acpi files"
depends on PROC_FS
- default y
---help---
For backwards compatibility, this option allows
deprecated /proc/acpi/ files to exist, even when
@@ -61,7 +60,6 @@ config ACPI_PROCFS
/proc/acpi/info (/sys/modules/acpi/parameters/acpica_version)
/proc/acpi/dsdt (/sys/firmware/acpi/tables/DSDT)
/proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
- /proc/acpi/battery (/sys/class/power_supply)
/proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
/proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
@@ -69,7 +67,21 @@ config ACPI_PROCFS
and functions which do not yet exist in /sys.
Say N to delete /proc/acpi/ files that have moved to /sys/
-
+config ACPI_PROCFS_POWER
+ bool "Deprecated power /proc/acpi folders"
+ depends on PROC_FS
+ default y
+ ---help---
+ For backwards compatibility, this option allows
+ deprecated power /proc/acpi/ folders to exist, even when
+ they have been replaced by functions in /sys.
+ The deprecated folders (and their replacements) include:
+ /proc/acpi/battery/* (/sys/class/power_supply/*)
+ /proc/acpi/ac_adapter/* (sys/class/power_supply/*)
+ This option has no effect on /proc/acpi/ folders
+ and functions, which do not yet exist in /sys
+
+ Say N to delete power /proc/acpi/ folders that have moved to /sys/
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 54e3ab0e5fc..456446f9007 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -58,6 +58,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
-obj-y += cm_sbs.o
+obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_SBS) += sbshc.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 30238f6ff23..76ed4f52beb 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -27,7 +27,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#endif
@@ -51,7 +51,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
MODULE_LICENSE("GPL");
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
@@ -86,7 +86,7 @@ struct acpi_ac {
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
static const struct file_operations acpi_ac_fops = {
.open = acpi_ac_open_fs,
.read = seq_read,
@@ -136,7 +136,7 @@ static int acpi_ac_get_state(struct acpi_ac *ac)
return 0;
}
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -275,7 +275,7 @@ static int acpi_ac_add(struct acpi_device *device)
if (result)
goto end;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
result = acpi_ac_add_fs(device);
#endif
if (result)
@@ -300,7 +300,7 @@ static int acpi_ac_add(struct acpi_device *device)
end:
if (result) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_remove_fs(device);
#endif
kfree(ac);
@@ -339,7 +339,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
ACPI_ALL_NOTIFY, acpi_ac_notify);
if (ac->charger.dev)
power_supply_unregister(&ac->charger);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_remove_fs(device);
#endif
@@ -355,7 +355,7 @@ static int __init acpi_ac_init(void)
if (acpi_disabled)
return -ENODEV;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir)
return -ENODEV;
@@ -363,7 +363,7 @@ static int __init acpi_ac_init(void)
result = acpi_bus_register_driver(&acpi_ac_driver);
if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_unlock_ac_dir(acpi_ac_dir);
#endif
return -ENODEV;
@@ -377,7 +377,7 @@ static void __exit acpi_ac_exit(void)
acpi_bus_unregister_driver(&acpi_ac_driver);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_unlock_ac_dir(acpi_ac_dir);
#endif
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 192c244f619..7d6be23eff8 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -31,7 +31,7 @@
#include <linux/types.h>
#include <linux/jiffies.h>
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
@@ -63,7 +63,7 @@ static unsigned int cache_time = 1000;
module_param(cache_time, uint, 0644);
MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
@@ -153,6 +153,8 @@ static int acpi_battery_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (battery->state == 0)
val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = acpi_battery_present(battery);
@@ -221,7 +223,7 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
};
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
inline char *acpi_battery_units(struct acpi_battery *battery)
{
return (battery->power_unit)?"mA":"mW";
@@ -479,7 +481,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
FS Interface (/proc)
-------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
static struct proc_dir_entry *acpi_battery_dir;
static int acpi_battery_print_info(struct seq_file *seq, int result)
@@ -786,7 +788,7 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_driver_data(device) = battery;
mutex_init(&battery->lock);
acpi_battery_update(battery);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
result = acpi_battery_add_fs(device);
if (result)
goto end;
@@ -804,7 +806,7 @@ static int acpi_battery_add(struct acpi_device *device)
device->status.battery_present ? "present" : "absent");
end:
if (result) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device);
#endif
kfree(battery);
@@ -823,7 +825,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device);
#endif
sysfs_remove_battery(battery);
@@ -859,13 +861,13 @@ static int __init acpi_battery_init(void)
{
if (acpi_disabled)
return -ENODEV;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir)
return -ENODEV;
#endif
if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_unlock_battery_dir(acpi_battery_dir);
#endif
return -ENODEV;
@@ -876,7 +878,7 @@ static int __init acpi_battery_init(void)
static void __exit acpi_battery_exit(void)
{
acpi_bus_unregister_driver(&acpi_battery_driver);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_unlock_battery_dir(acpi_battery_dir);
#endif
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 06b78e5e33a..d411017f8c0 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -47,6 +47,9 @@
#undef PREFIX
#define PREFIX "ACPI: EC: "
+/* Uncomment next line to get verbose print outs*/
+/* #define DEBUG */
+
/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
@@ -75,7 +78,10 @@ enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
- EC_FLAGS_ONLY_IBF_GPE, /* Expect GPE only for IBF = 0 event */
+ EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
+ EC_FLAGS_ADDRESS, /* Address is being written */
+ EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
+ EC_FLAGS_WDATA, /* Data is being written */
};
static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -131,21 +137,27 @@ static struct acpi_ec {
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
{
- return inb(ec->command_addr);
+ u8 x = inb(ec->command_addr);
+ pr_debug(PREFIX "---> status = 0x%2x\n", x);
+ return x;
}
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
+ u8 x = inb(ec->data_addr);
+ pr_debug(PREFIX "---> data = 0x%2x\n", x);
return inb(ec->data_addr);
}
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
{
+ pr_debug(PREFIX "<--- command = 0x%2x\n", command);
outb(command, ec->command_addr);
}
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
{
+ pr_debug(PREFIX "<--- data = 0x%2x\n", data);
outb(data, ec->data_addr);
}
@@ -166,38 +178,54 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{
+ int ret = 0;
+ if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
+ test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
+ force_poll = 1;
+ if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
+ test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
+ force_poll = 1;
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
msecs_to_jiffies(ACPI_EC_DELAY)))
- return 0;
+ goto end;
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (acpi_ec_check_status(ec, event)) {
- if (event == ACPI_EC_EVENT_OBF_1) {
- /* miss OBF = 1 GPE, don't expect it anymore */
- printk(KERN_INFO PREFIX "missing OBF_1 confirmation,"
- "switching to degraded mode.\n");
- set_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags);
+ if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
+ /* miss address GPE, don't expect it anymore */
+ pr_info(PREFIX "missing address confirmation, "
+ "don't expect it any longer.\n");
+ set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
+ } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
+ /* miss write data GPE, don't expect it */
+ pr_info(PREFIX "missing write data confirmation, "
+ "don't expect it any longer.\n");
+ set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
} else {
/* missing GPEs, switch back to poll mode */
- printk(KERN_INFO PREFIX "missing IBF_1 confirmations,"
- "switch off interrupt mode.\n");
+ if (printk_ratelimit())
+ pr_info(PREFIX "missing confirmations, "
+ "switch off interrupt mode.\n");
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
}
- return 0;
+ goto end;
}
} else {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
- return 0;
+ goto end;
}
}
- printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
+ pr_err(PREFIX "acpi_ec_wait timeout,"
" status = %d, expect_event = %d\n",
acpi_ec_read_status(ec), event);
- return -ETIME;
+ ret = -ETIME;
+ end:
+ clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
+ return ret;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -208,22 +236,26 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
int result = 0;
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_cmd(ec, command);
-
+ pr_debug(PREFIX "transaction start\n");
for (; wdata_len > 0; --wdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
- printk(KERN_ERR PREFIX
+ pr_err(PREFIX
"write_cmd timeout, command = %d\n", command);
goto end;
}
+ /* mark the address byte written to EC */
+ if (rdata_len + wdata_len > 1)
+ set_bit(EC_FLAGS_ADDRESS, &ec->flags);
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
+ set_bit(EC_FLAGS_WDATA, &ec->flags);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
- printk(KERN_ERR PREFIX
+ pr_err(PREFIX
"finish-write timeout, command = %d\n", command);
goto end;
}
@@ -231,12 +263,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
for (; rdata_len > 0; --rdata_len) {
- if (test_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags))
- force_poll = 1;
result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll);
if (result) {
- printk(KERN_ERR PREFIX "read timeout, command = %d\n",
- command);
+ pr_err(PREFIX "read timeout, command = %d\n", command);
goto end;
}
/* Don't expect GPE after last read */
@@ -245,6 +274,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
*(rdata++) = acpi_ec_read_data(ec);
}
end:
+ pr_debug(PREFIX "transaction end\n");
return result;
}
@@ -273,8 +303,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
if (status) {
- printk(KERN_ERR PREFIX
- "input buffer is not empty, aborting transaction\n");
+ pr_err(PREFIX "input buffer is not empty, "
+ "aborting transaction\n");
goto end;
}
@@ -488,6 +518,7 @@ static u32 acpi_ec_gpe_handler(void *data)
acpi_status status = AE_OK;
struct acpi_ec *ec = data;
+ pr_debug(PREFIX "~~~> interrupt\n");
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
@@ -498,8 +529,9 @@ static u32 acpi_ec_gpe_handler(void *data)
acpi_ec_gpe_query, ec);
} else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
/* this is non-query, must be confirmation */
- printk(KERN_INFO PREFIX "non-query interrupt received,"
- " switching to interrupt mode\n");
+ if (printk_ratelimit())
+ pr_info(PREFIX "non-query interrupt received,"
+ " switching to interrupt mode\n");
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
}
@@ -701,10 +733,10 @@ static void ec_remove_handlers(struct acpi_ec *ec)
{
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
- printk(KERN_ERR PREFIX "failed to remove space handler\n");
+ pr_err(PREFIX "failed to remove space handler\n");
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler)))
- printk(KERN_ERR PREFIX "failed to remove gpe handler\n");
+ pr_err(PREFIX "failed to remove gpe handler\n");
ec->handlers_installed = 0;
}
@@ -747,9 +779,9 @@ static int acpi_ec_add(struct acpi_device *device)
first_ec = ec;
acpi_driver_data(device) = ec;
acpi_ec_add_fs(device);
- printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
+ pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
- printk(KERN_INFO PREFIX "driver started in %s mode\n",
+ pr_info(PREFIX "driver started in %s mode\n",
(test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll");
return 0;
}
@@ -875,18 +907,26 @@ int __init acpi_ec_ecdt_probe(void)
status = acpi_get_table(ACPI_SIG_ECDT, 1,
(struct acpi_table_header **)&ecdt_ptr);
if (ACPI_SUCCESS(status)) {
- printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
+ pr_info(PREFIX "EC description table is found, configuring boot EC\n");
boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
} else {
+ /* This workaround is needed only on some broken machines,
+ * which require early EC, but fail to provide ECDT */
+ acpi_handle x;
printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
boot_ec, NULL);
/* Check that acpi_get_devices actually find something */
if (ACPI_FAILURE(status) || !boot_ec->handle)
goto error;
+ /* We really need to limit this workaround, the only ASUS,
+ * which needs it, has fake EC._INI method, so use it as flag.
+ */
+ if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
+ goto error;
}
ret = ec_install_handlers(boot_ec);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index aabc6ca4a81..e3a673a0084 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -387,17 +387,14 @@ acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
if (!value)
value = &dummy;
- switch (width) {
- case 8:
+ *value = 0;
+ if (width <= 8) {
*(u8 *) value = inb(port);
- break;
- case 16:
+ } else if (width <= 16) {
*(u16 *) value = inw(port);
- break;
- case 32:
+ } else if (width <= 32) {
*(u32 *) value = inl(port);
- break;
- default:
+ } else {
BUG();
}
@@ -408,17 +405,13 @@ EXPORT_SYMBOL(acpi_os_read_port);
acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
{
- switch (width) {
- case 8:
+ if (width <= 8) {
outb(value, port);
- break;
- case 16:
+ } else if (width <= 16) {
outw(value, port);
- break;
- case 32:
+ } else if (width <= 32) {
outl(value, port);
- break;
- default:
+ } else {
BUG();
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 235a51e328c..015689d295c 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -612,12 +612,6 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
request_region(pr->throttling.address, 6, "ACPI CPU throttle");
}
-#ifdef CONFIG_CPU_FREQ
- acpi_processor_ppc_has_changed(pr);
-#endif
- acpi_processor_get_throttling_info(pr);
- acpi_processor_get_limit_info(pr);
-
return 0;
}
@@ -647,7 +641,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
*/
if (processor_device_array[pr->id] != NULL &&
processor_device_array[pr->id] != device) {
- printk(KERN_WARNING "BIOS reported wrong ACPI id"
+ printk(KERN_WARNING "BIOS reported wrong ACPI id "
"for the processor\n");
return -ENODEV;
}
@@ -665,6 +659,12 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
/* _PDC call should be done before doing anything else (if reqd.). */
arch_acpi_processor_init_pdc(pr);
acpi_processor_set_pdc(pr);
+#ifdef CONFIG_CPU_FREQ
+ acpi_processor_ppc_has_changed(pr);
+#endif
+ acpi_processor_get_throttling_info(pr);
+ acpi_processor_get_limit_info(pr);
+
acpi_processor_power_init(pr, device);
@@ -684,7 +684,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_processor *pr = data;
struct acpi_device *device = NULL;
-
+ int saved;
if (!pr)
return;
@@ -694,7 +694,10 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
switch (event) {
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
+ saved = pr->performance_platform_limit;
acpi_processor_ppc_has_changed(pr);
+ if (saved == pr->performance_platform_limit)
+ break;
acpi_bus_generate_proc_event(device, event,
pr->performance_platform_limit);
acpi_bus_generate_netlink_event(device->pnp.device_class,
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f996d0e3768..7b6c20eeeaf 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -197,6 +197,19 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
}
+static void acpi_safe_halt(void)