Pull bugzilla-9327 into release branch

Conflicts:

	drivers/acpi/ec.c

Signed-off-by: Len Brown <len.brown@intel.com>
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index ec49926..10c041c 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 @@
 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.
+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.
+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 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.
+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 @@
 
 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 @@
 		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 f63e5ff..a25db51 100644
--- a/arch/x86/kernel/acpi/processor.c
+++ b/arch/x86/kernel/acpi/processor.c
@@ -49,6 +49,9 @@
 	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 79475d2..da42de2 100644
--- a/arch/x86/kernel/acpi/sleep_64.c
+++ b/arch/x86/kernel/acpi/sleep_64.c
@@ -115,6 +115,3 @@
 
 __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 f35c6eb..6bb80ea 100644
--- a/arch/x86/kernel/io_apic_32.c
+++ b/arch/x86/kernel/io_apic_32.c
@@ -962,7 +962,7 @@
 #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 @@
 	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 953328b..435a8c9 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -546,7 +546,7 @@
 #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 @@
 	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 @@
 	}
 }
 #endif
+
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 7e35078..0234f28 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -13,7 +13,7 @@
 	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 087a702..b9f923e 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -50,7 +50,6 @@
 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 @@
 	  /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 @@
 	  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 54e3ab0..456446f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -58,6 +58,6 @@
 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 30238f6..76ed4f5 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_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 @@
 
 #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 @@
 	return 0;
 }
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
@@ -275,7 +275,7 @@
 	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 @@
 
       end:
 	if (result) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 		acpi_ac_remove_fs(device);
 #endif
 		kfree(ac);
@@ -339,7 +339,7 @@
 					    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 @@
 	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 @@
 
 	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 @@
 
 	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 192c244f..7d6be23 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 @@
 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 @@
 			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 @@
 	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 @@
                               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 @@
 	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 @@
 	       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 @@
 	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 @@
 {
 	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 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 7d6b841..d411017 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -913,12 +913,20 @@
 		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 aabc6ca..e3a673a 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -387,17 +387,14 @@
 	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 @@
 
 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 692b2a0..015689d29 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -612,12 +612,6 @@
 		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 @@
 	 */
 	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 @@
 	/* _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);
 
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f996d0e..7b6c20e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -197,6 +197,19 @@
 		return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
 }
 
+static void acpi_safe_halt(void)
+{
+	current_thread_info()->status &= ~TS_POLLING;
+	/*
+	 * TS_POLLING-cleared state must be visible before we
+	 * test NEED_RESCHED:
+	 */
+	smp_mb();
+	if (!need_resched())
+		safe_halt();
+	current_thread_info()->status |= TS_POLLING;
+}
+
 #ifndef CONFIG_CPU_IDLE
 
 static void
@@ -239,19 +252,6 @@
 	return;
 }
 
-static void acpi_safe_halt(void)
-{
-	current_thread_info()->status &= ~TS_POLLING;
-	/*
-	 * TS_POLLING-cleared state must be visible before we
-	 * test NEED_RESCHED:
-	 */
-	smp_mb();
-	if (!need_resched())
-		safe_halt();
-	current_thread_info()->status |= TS_POLLING;
-}
-
 static atomic_t c3_cpu_count;
 
 /* Common C-state entry for C2, C3, .. */
@@ -1373,15 +1373,7 @@
 	if (pr->flags.bm_check)
 		acpi_idle_update_bm_rld(pr, cx);
 
-	current_thread_info()->status &= ~TS_POLLING;
-	/*
-	 * TS_POLLING-cleared state must be visible before we test
-	 * NEED_RESCHED:
-	 */
-	smp_mb();
-	if (!need_resched())
-		safe_halt();
-	current_thread_info()->status |= TS_POLLING;
+	acpi_safe_halt();
 
 	cx->usage++;
 
@@ -1399,6 +1391,8 @@
 	struct acpi_processor *pr;
 	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 	u32 t1, t2;
+	int sleep_ticks = 0;
+
 	pr = processors[smp_processor_id()];
 
 	if (unlikely(!pr))
@@ -1428,6 +1422,8 @@
 		ACPI_FLUSH_CPU_CACHE();
 
 	t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+	/* Tell the scheduler that we are going deep-idle: */
+	sched_clock_idle_sleep_event();
 	acpi_state_timer_broadcast(pr, cx, 1);
 	acpi_idle_do_entry(cx);
 	t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
@@ -1436,6 +1432,10 @@
 	/* TSC could halt in idle, so notify users */
 	mark_tsc_unstable("TSC halts in idle");;
 #endif
+	sleep_ticks = ticks_elapsed(t1, t2);
+
+	/* Tell the scheduler how much we idled: */
+	sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
 
 	local_irq_enable();
 	current_thread_info()->status |= TS_POLLING;
@@ -1443,7 +1443,7 @@
 	cx->usage++;
 
 	acpi_state_timer_broadcast(pr, cx, 0);
-	cx->time += ticks_elapsed(t1, t2);
+	cx->time += sleep_ticks;
 	return ticks_elapsed_in_us(t1, t2);
 }
 
@@ -1463,6 +1463,8 @@
 	struct acpi_processor *pr;
 	struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 	u32 t1, t2;
+	int sleep_ticks = 0;
+
 	pr = processors[smp_processor_id()];
 
 	if (unlikely(!pr))
@@ -1471,6 +1473,15 @@
 	if (acpi_idle_suspend)
 		return(acpi_idle_enter_c1(dev, state));
 
+	if (acpi_idle_bm_check()) {
+		if (dev->safe_state) {
+			return dev->safe_state->enter(dev, dev->safe_state);
+		} else {
+			acpi_safe_halt();
+			return 0;
+		}
+	}
+
 	local_irq_disable();
 	current_thread_info()->status &= ~TS_POLLING;
 	/*
@@ -1485,38 +1496,45 @@
 		return 0;
 	}
 
+	/* Tell the scheduler that we are going deep-idle: */
+	sched_clock_idle_sleep_event();
 	/*
 	 * Must be done before busmaster disable as we might need to
 	 * access HPET !
 	 */
 	acpi_state_timer_broadcast(pr, cx, 1);
 
-	if (acpi_idle_bm_check()) {
-		cx = pr->power.bm_state;
+	acpi_idle_update_bm_rld(pr, cx);
 
-		acpi_idle_update_bm_rld(pr, cx);
-
-		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-		acpi_idle_do_entry(cx);
-		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-	} else {
-		acpi_idle_update_bm_rld(pr, cx);
-
+	/*
+	 * disable bus master
+	 * bm_check implies we need ARB_DIS
+	 * !bm_check implies we need cache flush
+	 * bm_control implies whether we can do ARB_DIS
+	 *
+	 * That leaves a case where bm_check is set and bm_control is
+	 * not set. In that case we cannot do much, we enter C3
+	 * without doing anything.
+	 */
+	if (pr->flags.bm_check && pr->flags.bm_control) {
 		spin_lock(&c3_lock);
 		c3_cpu_count++;
 		/* Disable bus master arbitration when all CPUs are in C3 */
 		if (c3_cpu_count == num_online_cpus())
 			acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
 		spin_unlock(&c3_lock);
+	} else if (!pr->flags.bm_check) {
+		ACPI_FLUSH_CPU_CACHE();
+	}
 
-		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-		acpi_idle_do_entry(cx);
-		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+	t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+	acpi_idle_do_entry(cx);
+	t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
+	/* Re-enable bus master arbitration */
+	if (pr->flags.bm_check && pr->flags.bm_control) {
 		spin_lock(&c3_lock);
-		/* Re-enable bus master arbitration */
-		if (c3_cpu_count == num_online_cpus())
-			acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
+		acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
 		c3_cpu_count--;
 		spin_unlock(&c3_lock);
 	}
@@ -1525,6 +1543,9 @@
 	/* TSC could halt in idle, so notify users */
 	mark_tsc_unstable("TSC halts in idle");
 #endif
+	sleep_ticks = ticks_elapsed(t1, t2);
+	/* Tell the scheduler how much we idled: */
+	sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
 
 	local_irq_enable();
 	current_thread_info()->status |= TS_POLLING;
@@ -1532,7 +1553,7 @@
 	cx->usage++;
 
 	acpi_state_timer_broadcast(pr, cx, 0);
-	cx->time += ticks_elapsed(t1, t2);
+	cx->time += sleep_ticks;
 	return ticks_elapsed_in_us(t1, t2);
 }
 
@@ -1584,12 +1605,14 @@
 			case ACPI_STATE_C1:
 			state->flags |= CPUIDLE_FLAG_SHALLOW;
 			state->enter = acpi_idle_enter_c1;
+			dev->safe_state = state;
 			break;
 
 			case ACPI_STATE_C2:
 			state->flags |= CPUIDLE_FLAG_BALANCED;
 			state->flags |= CPUIDLE_FLAG_TIME_VALID;
 			state->enter = acpi_idle_enter_simple;
+			dev->safe_state = state;
 			break;
 
 			case ACPI_STATE_C3:
@@ -1610,14 +1633,6 @@
 	if (!count)
 		return -EINVAL;
 
-	/* find the deepest state that can handle active BM */
-	if (pr->flags.bm_check) {
-		for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++)
-			if (pr->power.states[i].type == ACPI_STATE_C3)
-				break;
-		pr->power.bm_state = &pr->power.states[i-1];
-	}
-
 	return 0;
 }
 
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 0b8204e..c26c61f 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -70,7 +70,55 @@
 
 int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
 {
-	return acpi_processor_get_platform_limit(pr);
+	int result = 0;
+	int throttling_limit;
+	int current_state;
+	struct acpi_processor_limit *limit;
+	int target_state;
+
+	result = acpi_processor_get_platform_limit(pr);
+	if (result) {
+		/* Throttling Limit is unsupported */
+		return result;
+	}
+
+	throttling_limit = pr->throttling_platform_limit;
+	if (throttling_limit >= pr->throttling.state_count) {
+		/* Uncorrect Throttling Limit */
+		return -EINVAL;
+	}
+
+	current_state = pr->throttling.state;
+	if (current_state > throttling_limit) {
+		/*
+		 * The current state can meet the requirement of
+		 * _TPC limit. But it is reasonable that OSPM changes
+		 * t-states from high to low for better performance.
+		 * Of course the limit condition of thermal
+		 * and user should be considered.
+		 */
+		limit = &pr->limit;
+		target_state = throttling_limit;
+		if (limit->thermal.tx > target_state)
+			target_state = limit->thermal.tx;
+		if (limit->user.tx > target_state)
+			target_state = limit->user.tx;
+	} else if (current_state == throttling_limit) {
+		/*
+		 * Unnecessary to change the throttling state
+		 */
+		return 0;
+	} else {
+		/*
+		 * If the current state is lower than the limit of _TPC, it
+		 * will be forced to switch to the throttling state defined
+		 * by throttling_platfor_limit.
+		 * Because the previous state meets with the limit condition
+		 * of thermal and user, it is unnecessary to check it again.
+		 */
+		target_state = throttling_limit;
+	}
+	return acpi_processor_set_throttling(pr, target_state);
 }
 
 /*
@@ -83,6 +131,7 @@
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *ptc = NULL;
 	union acpi_object obj = { 0 };
+	struct acpi_processor_throttling *throttling;
 
 	status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
@@ -134,6 +183,22 @@
 	memcpy(&pr->throttling.status_register, obj.buffer.pointer,
 	       sizeof(struct acpi_ptc_register));
 
+	throttling = &pr->throttling;
+
+	if ((throttling->control_register.bit_width +
+		throttling->control_register.bit_offset) > 32) {
+		printk(KERN_ERR PREFIX "Invalid _PTC control register\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	if ((throttling->status_register.bit_width +
+		throttling->status_register.bit_offset) > 32) {
+		printk(KERN_ERR PREFIX "Invalid _PTC status register\n");
+		result = -EFAULT;
+		goto end;
+	}
+
       end:
 	kfree(buffer.pointer);
 
@@ -328,44 +393,132 @@
 	return 0;
 }
 
-static int acpi_read_throttling_status(struct acpi_processor_throttling
-				       *throttling)
+#ifdef CONFIG_X86
+static int acpi_throttling_rdmsr(struct acpi_processor *pr,
+					acpi_integer * value)
 {
-	int value = -1;
+	struct cpuinfo_x86 *c;
+	u64 msr_high, msr_low;
+	unsigned int cpu;
+	u64 msr = 0;
+	int ret = -1;
+
+	cpu = pr->id;
+	c = &cpu_data(cpu);
+
+	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
+		!cpu_has(c, X86_FEATURE_ACPI)) {
+		printk(KERN_ERR PREFIX
+			"HARDWARE addr space,NOT supported yet\n");
+	} else {
+		msr_low = 0;
+		msr_high = 0;
+		rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL,
+			(u32 *)&msr_low , (u32 *) &msr_high);
+		msr = (msr_high << 32) | msr_low;
+		*value = (acpi_integer) msr;
+		ret = 0;
+	}
+	return ret;
+}
+
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+{
+	struct cpuinfo_x86 *c;
+	unsigned int cpu;
+	int ret = -1;
+	u64 msr;
+
+	cpu = pr->id;
+	c = &cpu_data(cpu);
+
+	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
+		!cpu_has(c, X86_FEATURE_ACPI)) {
+		printk(KERN_ERR PREFIX
+			"HARDWARE addr space,NOT supported yet\n");
+	} else {
+		msr = value;
+		wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL,
+			msr & 0xffffffff, msr >> 32);
+		ret = 0;
+	}
+	return ret;
+}
+#else
+static int acpi_throttling_rdmsr(struct acpi_processor *pr,
+				acpi_integer * value)
+{
+	printk(KERN_ERR PREFIX
+		"HARDWARE addr space,NOT supported yet\n");
+	return -1;
+}
+
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+{
+	printk(KERN_ERR PREFIX
+		"HARDWARE addr space,NOT supported yet\n");
+	return -1;
+}
+#endif
+
+static int acpi_read_throttling_status(struct acpi_processor *pr,
+					acpi_integer *value)
+{
+	u32 bit_width, bit_offset;
+	u64 ptc_value;
+	u64 ptc_mask;
+	struct acpi_processor_throttling *throttling;
+	int ret = -1;
+
+	throttling = &pr->throttling;
 	switch (throttling->status_register.space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_IO:
+		ptc_value = 0;
+		bit_width = throttling->status_register.bit_width;
+		bit_offset = throttling->status_register.bit_offset;
+
 		acpi_os_read_port((acpi_io_address) throttling->status_register.
-				  address, &value,
-				  (u32) throttling->status_register.bit_width *
-				  8);
+				  address, (u32 *) &ptc_value,
+				  (u32) (bit_width + bit_offset));
+		ptc_mask = (1 << bit_width) - 1;
+		*value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask);
+		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		printk(KERN_ERR PREFIX
-		       "HARDWARE addr space,NOT supported yet\n");
+		ret = acpi_throttling_rdmsr(pr, value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
 		       (u32) (throttling->status_register.space_id));
 	}
-	return value;
+	return ret;
 }
 
-static int acpi_write_throttling_state(struct acpi_processor_throttling
-				       *throttling, int value)
+static int acpi_write_throttling_state(struct acpi_processor *pr,
+				acpi_integer value)
 {
+	u32 bit_width, bit_offset;
+	u64 ptc_value;
+	u64 ptc_mask;
+	struct acpi_processor_throttling *throttling;
 	int ret = -1;
 
+	throttling = &pr->throttling;
 	switch (throttling->control_register.space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_IO:
+		bit_width = throttling->control_register.bit_width;
+		bit_offset = throttling->control_register.bit_offset;
+		ptc_mask = (1 << bit_width) - 1;
+		ptc_value = value & ptc_mask;
+
 		acpi_os_write_port((acpi_io_address) throttling->
-				   control_register.address, value,
-				   (u32) throttling->control_register.
-				   bit_width * 8);
+					control_register.address,
+					(u32) (ptc_value << bit_offset),
+					(u32) (bit_width + bit_offset));
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		printk(KERN_ERR PREFIX
-		       "HARDWARE addr space,NOT supported yet\n");
+		ret = acpi_throttling_wrmsr(pr, value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
@@ -374,7 +527,8 @@
 	return ret;
 }
 
-static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
+static int acpi_get_throttling_state(struct acpi_processor *pr,
+				acpi_integer value)
 {
 	int i;
 
@@ -390,22 +544,26 @@
 	return i;
 }
 
-static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
+static int acpi_get_throttling_value(struct acpi_processor *pr,
+			int state, acpi_integer *value)
 {
-	int value = -1;
+	int ret = -1;
+
 	if (state >= 0 && state <= pr->throttling.state_count) {
 		struct acpi_processor_tx_tss *tx =
 		    (struct acpi_processor_tx_tss *)&(pr->throttling.
 						      states_tss[state]);
-		value = tx->control;
+		*value = tx->control;
+		ret = 0;
 	}
-	return value;
+	return ret;
 }
 
 static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
 {
 	int state = 0;
-	u32 value = 0;
+	int ret;
+	acpi_integer value;
 
 	if (!pr)
 		return -EINVAL;
@@ -415,8 +573,9 @@
 
 	pr->throttling.state = 0;
 	local_irq_disable();
-	value = acpi_read_throttling_status(&pr->throttling);
-	if (value >= 0) {
+	value = 0;
+	ret = acpi_read_throttling_status(pr, &value);
+	if (ret >= 0) {
 		state = acpi_get_throttling_state(pr, value);
 		pr->throttling.state = state;
 	}
@@ -430,6 +589,40 @@
 	return pr->throttling.acpi_processor_get_throttling(pr);
 }
 
+static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
+{
+	int i, step;
+
+	if (!pr->throttling.address) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
+		return -EINVAL;
+	} else if (!pr->throttling.duty_width) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
+		return -EINVAL;
+	}
+	/* TBD: Support duty_cycle values that span bit 4. */
+	else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
+		printk(KERN_WARNING PREFIX "duty_cycle spans bit 4\n");
+		return -EINVAL;
+	}
+
+	pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
+
+	/*
+	 * Compute state values. Note that throttling displays a linear power
+	 * performance relationship (at 50% performance the CPU will consume
+	 * 50% power).  Values are in 1/10th of a percent to preserve accuracy.
+	 */
+
+	step = (1000 / pr->throttling.state_count);
+
+	for (i = 0; i < pr->throttling.state_count; i++) {
+		pr->throttling.states[i].performance = 1000 - step * i;
+		pr->throttling.states[i].power = 1000 - step * i;
+	}
+	return 0;
+}
+
 static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
 					      int state)
 {
@@ -506,7 +699,8 @@
 static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
 					     int state)
 {
-	u32 value = 0;
+	int ret;
+	acpi_integer value;
 
 	if (!pr)
 		return -EINVAL;
@@ -524,10 +718,10 @@
 		return -EPERM;
 
 	local_irq_disable();
-
-	value = acpi_get_throttling_value(pr, state);
-	if (value >= 0) {
-		acpi_write_throttling_state(&pr->throttling, value);
+	value = 0;
+	ret = acpi_get_throttling_value(pr, state, &value);
+	if (ret >= 0) {
+		acpi_write_throttling_state(pr, value);
 		pr->throttling.state = state;
 	}
 	local_irq_enable();
@@ -543,8 +737,6 @@
 int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 {
 	int result = 0;
-	int step = 0;
-	int i = 0;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -563,6 +755,8 @@
 		acpi_processor_get_throttling_states(pr) ||
 		acpi_processor_get_platform_limit(pr))
 	{
+		if (acpi_processor_get_fadt_info(pr))
+			return 0;
 		pr->throttling.acpi_processor_get_throttling =
 		    &acpi_processor_get_throttling_fadt;
 		pr->throttling.acpi_processor_set_throttling =
@@ -576,19 +770,6 @@
 
 	acpi_processor_get_tsd(pr);
 
-	if (!pr->throttling.address) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
-		return 0;
-	} else if (!pr->throttling.duty_width) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
-		return 0;
-	}
-	/* TBD: Support duty_cycle values that span bit 4. */
-	else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
-		printk(KERN_WARNING PREFIX "duty_cycle spans bit 4\n");
-		return 0;
-	}
-
 	/*
 	 * PIIX4 Errata: We don't support throttling on the original PIIX4.
 	 * This shouldn't be an issue as few (if any) mobile systems ever
@@ -600,21 +781,6 @@
 		return 0;
 	}
 
-	pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
-
-	/*
-	 * Compute state values. Note that throttling displays a linear power/
-	 * performance relationship (at 50% performance the CPU will consume
-	 * 50% power).  Values are in 1/10th of a percent to preserve accuracy.
-	 */
-
-	step = (1000 / pr->throttling.state_count);
-
-	for (i = 0; i < pr->throttling.state_count; i++) {
-		pr->throttling.states[i].performance = step * i;
-		pr->throttling.states[i].power = step * i;
-	}
-
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
 			  pr->throttling.state_count));
 
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 90fd09c..6045cdb 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -29,7 +29,7 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
@@ -88,7 +88,7 @@
 struct acpi_battery {
 	struct power_supply bat;
 	struct acpi_sbs *sbs;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 	struct proc_dir_entry *proc_entry;
 #endif
 	unsigned long update_time;
@@ -113,6 +113,7 @@
 	u16 spec;
 	u8 id;
 	u8 present:1;
+	u8 have_sysfs_alarm:1;
 };
 
 #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
@@ -122,7 +123,7 @@
 	struct acpi_device *device;
 	struct acpi_smb_hc *hc;
 	struct mutex lock;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 	struct proc_dir_entry *charger_entry;
 #endif
 	struct acpi_battery battery[MAX_SBS_BAT];
@@ -468,7 +469,7 @@
                               FS Interface (/proc/acpi)
    -------------------------------------------------------------------------- */
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 /* Generic Routines */
 static int
 acpi_sbs_add_fs(struct proc_dir_entry **dir,
@@ -789,7 +790,7 @@
 		return result;
 
 	sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 	acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir,
 			battery->name, &acpi_battery_info_fops,
 			&acpi_battery_state_fops, &acpi_battery_alarm_fops,
@@ -808,7 +809,13 @@
 	}
 	battery->bat.get_property = acpi_sbs_battery_get_property;
 	result = power_supply_register(&sbs->device->dev, &battery->bat);
-	device_create_file(battery->bat.dev, &alarm_attr);
+	if (result)
+		goto end;
+	result = device_create_file(battery->bat.dev, &alarm_attr);
+	if (result)
+		goto end;
+	battery->have_sysfs_alarm = 1;
+      end:
 	printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
 	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
 	       battery->name, sbs->battery->present ? "present" : "absent");
@@ -817,14 +824,16 @@
 
 static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
 {
-	if (sbs->battery[id].bat.dev)
-		device_remove_file(sbs->battery[id].bat.dev, &alarm_attr);
-		power_supply_unregister(&sbs->battery[id].bat);
-#ifdef CONFIG_ACPI_PROCFS
-	if (sbs->battery[id].proc_entry) {
-		acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry),
-				   acpi_battery_dir);
+	struct acpi_battery *battery = &sbs->battery[id];
+
+	if (battery->bat.dev) {
+		if (battery->have_sysfs_alarm)
+			device_remove_file(battery->bat.dev, &alarm_attr);
+		power_supply_unregister(&battery->bat);
 	}
+#ifdef CONFIG_ACPI_PROCFS_POWER
+	if (battery->proc_entry)
+		acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
 #endif
 }
 
@@ -835,7 +844,7 @@
 	result = acpi_ac_get_present(sbs);
 	if (result)
 		goto end;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 	result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir,
 				 ACPI_AC_DIR_NAME, NULL,
 				 &acpi_ac_state_fops, NULL, sbs);
@@ -859,7 +868,7 @@
 {
 	if (sbs->charger.dev)
 		power_supply_unregister(&sbs->charger);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 	if (sbs->charger_entry)
 		acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
 #endif
@@ -965,7 +974,7 @@
 
 static void acpi_sbs_rmdirs(void)
 {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 	if (acpi_ac_dir) {
 		acpi_unlock_ac_dir(acpi_ac_dir);
 		acpi_ac_dir = NULL;
@@ -1004,7 +1013,7 @@
 
 	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;
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 5f1d85f..010f196 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -449,7 +449,7 @@
 			/* XSDT has NULL entry, RSDT is used */
 			address = rsdt_address;
 			table_entry_size = sizeof(u32);
-			ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry,"
+			ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, "
 					"using RSDT"));
 		}
 	}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index bac956b..44a0d9b 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -29,6 +29,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/input.h>
@@ -135,8 +136,8 @@
 	u8 attached_count;
 	struct acpi_video_bus_cap cap;
 	struct acpi_video_bus_flags flags;
-	struct semaphore sem;
 	struct list_head video_device_list;
+	struct mutex device_list_lock;	/* protects video_device_list */
 	struct proc_dir_entry *dir;
 	struct input_dev *input;
 	char phys[32];	/* for input device */
@@ -896,7 +897,7 @@
 {
 	struct seq_file *m = file->private_data;
 	struct acpi_video_device *dev = m->private;
-	char str[4] = { 0 };
+	char str[5] = { 0 };
 	unsigned int level = 0;
 	int i;
 
@@ -1436,9 +1437,9 @@
 			return -ENODEV;
 		}
 
-		down(&video->sem);
+		mutex_lock(&video->device_list_lock);
 		list_add_tail(&data->entry, &video->video_device_list);
-		up(&video->sem);
+		mutex_unlock(&video->device_list_lock);
 
 		acpi_video_device_add_fs(device);
 
@@ -1462,12 +1463,14 @@
 
 static void acpi_video_device_rebind(struct acpi_video_bus *video)
 {
-	struct list_head *node, *next;
-	list_for_each_safe(node, next, &video->video_device_list) {
-		struct acpi_video_device *dev =
-		    container_of(node, struct acpi_video_device, entry);
+	struct acpi_video_device *dev;
+
+	mutex_lock(&video->device_list_lock);
+
+	list_for_each_entry(dev, &video->video_device_list, entry)
 		acpi_video_device_bind(video, dev);
-	}
+
+	mutex_unlock(&video->device_list_lock);
 }
 
 /*
@@ -1592,30 +1595,33 @@
 
 static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
 {
-	struct list_head *node, *next;
+	struct list_head *node;
 	struct acpi_video_device *dev = NULL;
 	struct acpi_video_device *dev_next = NULL;
 	struct acpi_video_device *dev_prev = NULL;
 	unsigned long state;
 	int status = 0;
 
+	mutex_lock(&video->device_list_lock);
 
-	list_for_each_safe(node, next, &video->video_device_list) {
+	list_for_each(node, &video->video_device_list) {
 		dev = container_of(node, struct acpi_video_device, entry);
 		status = acpi_video_device_get_state(dev, &state);
 		if (state & 0x2) {
-			dev_next =
-			    container_of(node->next, struct acpi_video_device,
-					 entry);
-			dev_prev =
-			    container_of(node->prev, struct acpi_video_device,
-					 entry);
+			dev_next = container_of(node->next,
+					struct acpi_video_device, entry);
+			dev_prev = container_of(node->prev,
+					struct acpi_video_device, entry);
 			goto out;
 		}
 	}
+
 	dev_next = container_of(node->next, struct acpi_video_device, entry);
 	dev_prev = container_of(node->prev, struct acpi_video_device, entry);
-      out:
+
+ out:
+	mutex_unlock(&video->device_list_lock);
+
 	switch (event) {
 	case ACPI_VIDEO_NOTIFY_CYCLE:
 	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
@@ -1691,24 +1697,17 @@
 			   struct acpi_device *device)
 {
 	int status = 0;
-	struct list_head *node, *next;
-
+	struct acpi_device *dev;
 
 	acpi_video_device_enumerate(video);
 
-	list_for_each_safe(node, next, &device->children) {
-		struct acpi_device *dev =
-		    list_entry(node, struct acpi_device, node);
-
-		if (!dev)
-			continue;
+	list_for_each_entry(dev, &device->children, node) {
 
 		status = acpi_video_bus_get_one_device(dev, video);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
 			continue;
 		}
-
 	}
 	return status;
 }
@@ -1724,9 +1723,6 @@
 
 	video = device->video;
 
-	down(&video->sem);
-	list_del(&device->entry);
-	up(&video->sem);
 	acpi_video_device_remove_fs(device->dev);
 
 	status = acpi_remove_notify_handler(device->dev->handle,
@@ -1734,32 +1730,34 @@
 					    acpi_video_device_notify);
 	backlight_device_unregister(device->backlight);
 	video_output_unregister(device->output_dev);
+
 	return 0;
 }
 
 static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
 {
 	int status;
-	struct list_head *node, *next;
+	struct acpi_video_device *dev, *next;
 
+	mutex_lock(&video->device_list_lock);
 
-	list_for_each_safe(node, next, &video->video_device_list) {
-		struct acpi_video_device *data =
-		    list_entry(node, struct acpi_video_device, entry);
-		if (!data)
-			continue;
+	list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
 
-		status = acpi_video_bus_put_one_device(data);
+		status = acpi_video_bus_put_one_device(dev);
 		if (ACPI_FAILURE(status))
 			printk(KERN_WARNING PREFIX
 			       "hhuuhhuu bug in acpi video driver.\n");
 
-		if (data->brightness)
-			kfree(data->brightness->levels);
-		kfree(data->brightness);
-		kfree(data);
+		if (dev->brightness) {
+			kfree(dev->brightness->levels);
+			kfree(dev->brightness);
+		}
+		list_del(&dev->entry);
+		kfree(dev);
 	}
 
+	mutex_unlock(&video->device_list_lock);
+
 	return 0;
 }
 
@@ -1782,9 +1780,6 @@
 	struct input_dev *input;
 	int keycode;
 
-
-	printk("video bus notify\n");
-
 	if (!video)
 		return;
 
@@ -1897,14 +1892,10 @@
 static int instance;
 static int acpi_video_bus_add(struct acpi_device *device)
 {
-	int result = 0;
-	acpi_status status = 0;
-	struct acpi_video_bus *video = NULL;
+	acpi_status status;
+	struct acpi_video_bus *video;
 	struct input_dev *input;
-
-
-	if (!device)
-		return -EINVAL;
+	int error;
 
 	video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
 	if (!video)
@@ -1923,15 +1914,15 @@
 	acpi_driver_data(device) = video;
 
 	acpi_video_bus_find_cap(video);
-	result = acpi_video_bus_check(video);
-	if (result)
-		goto end;
+	error = acpi_video_bus_check(video);
+	if (error)
+		goto err_free_video;
 
-	result = acpi_video_bus_add_fs(device);
-	if (result)
-		goto end;
+	error = acpi_video_bus_add_fs(device);
+	if (error)
+		goto err_free_video;
 
-	init_MUTEX(&video->sem);
+	mutex_init(&video->device_list_lock);
 	INIT_LIST_HEAD(&video->video_device_list);
 
 	acpi_video_bus_get_devices(video, device);
@@ -1943,16 +1934,15 @@
 	if (ACPI_FAILURE(status)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Error installing notify handler\n"));
-		acpi_video_bus_stop_devices(video);
-		acpi_video_bus_put_devices(video);
-		kfree(video->attached_array);
-		acpi_video_bus_remove_fs(device);
-		result = -ENODEV;
-		goto end;
+		error = -ENODEV;
+		goto err_stop_video;
 	}
 
-
 	video->input = input = input_allocate_device();
+	if (!input) {
+		error = -ENOMEM;
+		goto err_uninstall_notify;
+	}
 
 	snprintf(video->phys, sizeof(video->phys),
 		"%s/video/input0", acpi_device_hid(video->device));
@@ -1961,6 +1951,7 @@
 	input->phys = video->phys;
 	input->id.bustype = BUS_HOST;
 	input->id.product = 0x06;
+	input->dev.parent = &device->dev;
 	input->evbit[0] = BIT(EV_KEY);
 	set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
 	set_bit(KEY_VIDEO_NEXT, input->keybit);
@@ -1971,18 +1962,10 @@
 	set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
 	set_bit(KEY_DISPLAY_OFF, input->keybit);
 	set_bit(KEY_UNKNOWN, input->keybit);
-	result = input_register_device(input);
-	if (result) {
-		acpi_remove_notify_handler(video->device->handle,
-						ACPI_DEVICE_NOTIFY,
-						acpi_video_bus_notify);
-		acpi_video_bus_stop_devices(video);
-		acpi_video_bus_put_devices(video);
-		kfree(video->attached_array);
-		acpi_video_bus_remove_fs(device);
-		goto end;
-        }
 
+	error = input_register_device(input);
+	if (error)
+		goto err_free_input_dev;
 
 	printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
 	       ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
@@ -1990,11 +1973,23 @@
 	       video->flags.rom ? "yes" : "no",
 	       video->flags.post ? "yes" : "no");
 
-      end:
-	if (result)
-		kfree(video);
+	return 0;
 
-	return result;
+ err_free_input_dev:
+	input_free_device(input);
+ err_uninstall_notify:
+	acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+				   acpi_video_bus_notify);
+ err_stop_video:
+	acpi_video_bus_stop_devices(video);
+	acpi_video_bus_put_devices(video);
+	kfree(video->attached_array);
+	acpi_video_bus_remove_fs(device);
+ err_free_video:
+	kfree(video);
+	acpi_driver_data(device) = NULL;
+
+	return error;
 }
 
 static int acpi_video_bus_remove(struct acpi_device *device, int type)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index e953276..ab23a32 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
  *  02110-1301, USA.
  */
 
-#define IBM_VERSION "0.16"
+#define IBM_VERSION "0.17"
 #define TPACPI_SYSFS_VERSION 0x020000
 
 /*
@@ -964,15 +964,15 @@
 		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */
 		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */
 		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */
-		KEY_BRIGHTNESSUP,	/* 0x0F: FN+HOME (brightness up) */
+		KEY_RESERVED,	/* 0x0F: FN+HOME (brightness up) */
 		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
-		KEY_BRIGHTNESSDOWN,	/* 0x10: FN+END (brightness down) */
+		KEY_RESERVED,	/* 0x10: FN+END (brightness down) */
 		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */
 		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */
 		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */
-		KEY_VOLUMEUP,	/* 0x14: VOLUME UP */
-		KEY_VOLUMEDOWN,	/* 0x15: VOLUME DOWN */
-		KEY_MUTE,	/* 0x16: MUTE */
+		KEY_RESERVED,	/* 0x14: VOLUME UP */
+		KEY_RESERVED,	/* 0x15: VOLUME DOWN */
+		KEY_RESERVED,	/* 0x16: MUTE */
 		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */
 		/* (assignments unknown, please report if found) */
 		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -993,9 +993,9 @@
 		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */
 		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */
 		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */
-		KEY_VOLUMEUP,	/* 0x14: VOLUME UP */
-		KEY_VOLUMEDOWN,	/* 0x15: VOLUME DOWN */
-		KEY_MUTE,	/* 0x16: MUTE */
+		KEY_RESERVED,	/* 0x14: VOLUME UP */
+		KEY_RESERVED,	/* 0x15: VOLUME DOWN */
+		KEY_RESERVED,	/* 0x16: MUTE */
 		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */
 		/* (assignments unknown, please report if found) */
 		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -1342,9 +1342,8 @@
 		return len;
 	}
 
-	res = mutex_lock_interruptible(&hotkey_mutex);
-	if (res < 0)
-		return res;
+	if (mutex_lock_interruptible(&hotkey_mutex))
+		return -ERESTARTSYS;
 	res = hotkey_get(&status, &mask);
 	mutex_unlock(&hotkey_mutex);
 	if (res)
@@ -1373,9 +1372,8 @@
 	if (!tp_features.hotkey)
 		return -ENODEV;
 
-	res = mutex_lock_interruptible(&hotkey_mutex);
-	if (res < 0)
-		return res;
+	if (mutex_lock_interruptible(&hotkey_mutex))
+		return -ERESTARTSYS;
 
 	res = hotkey_get(&status, &mask);
 	if (res)
@@ -3114,6 +3112,99 @@
 
 static struct mutex brightness_mutex;
 
+static int __init tpacpi_query_bcll_levels(acpi_handle handle)
+{
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	int rc;
+
+	if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+		obj = (union acpi_object *)buffer.pointer;
+		if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+			printk(IBM_ERR "Unknown BCLL data, "
+			       "please report this to %s\n", IBM_MAIL);
+			rc = 0;
+		} else {
+			rc = obj->package.count;
+		}
+	} else {
+		return 0;
+	}
+
+	kfree(buffer.pointer);
+	return rc;
+}
+
+static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
+					void *context, void **rv)
+{
+	char name[ACPI_PATH_SEGMENT_LENGTH];
+	struct acpi_buffer buffer = { sizeof(name), &name };
+
+	if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+	    !strncmp("BCLL", name, sizeof(name) - 1)) {
+		if (tpacpi_query_bcll_levels(handle) == 16) {
+			*rv = handle;
+			return AE_CTRL_TERMINATE;
+		} else {
+			return AE_OK;
+		}
+	} else {
+		return AE_OK;
+	}
+}
+
+static int __init brightness_check_levels(void)
+{
+	int status;
+	void *found_node = NULL;
+
+	if (!vid_handle) {
+		IBM_ACPIHANDLE_INIT(vid);
+	}
+	if (!vid_handle)
+		return 0;
+
+	/* Search for a BCLL package with 16 levels */
+	status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
+					brightness_find_bcll, NULL, &found_node);
+
+	return (ACPI_SUCCESS(status) && found_node != NULL);
+}
+
+static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
+					void *context, void **rv)
+{
+	char name[ACPI_PATH_SEGMENT_LENGTH];
+	struct acpi_buffer buffer = { sizeof(name), &name };
+
+	if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+	    !strncmp("_BCL", name, sizeof(name) - 1)) {
+		*rv = handle;
+		return AE_CTRL_TERMINATE;
+	} else {
+		return AE_OK;
+	}
+}
+
+static int __init brightness_check_std_acpi_support(void)
+{
+	int status;
+	void *found_node = NULL;
+
+	if (!vid_handle) {
+		IBM_ACPIHANDLE_INIT(vid);
+	}
+	if (!vid_handle)
+		return 0;
+
+	/* Search for a _BCL method, but don't execute it */
+	status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+	                             brightness_find_bcl, NULL, &found_node);
+
+	return (ACPI_SUCCESS(status) && found_node != NULL);
+}
+
 static int __init brightness_init(struct ibm_init_struct *iibm)
 {
 	int b;
@@ -3122,6 +3213,18 @@
 
 	mutex_init(&brightness_mutex);
 
+	if (!brightness_enable) {
+		dbg_printk(TPACPI_DBG_INIT,
+		           "brightness support disabled by module parameter\n");
+		return 1;
+	} else if (brightness_enable > 1) {
+		if (brightness_check_std_acpi_support()) {
+			printk(IBM_NOTICE
+			       "standard ACPI backlight interface available, not loading native one...\n");
+			return 1;
+		}
+	}
+
 	if (!brightness_mode) {
 		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
 			brightness_mode = 2;
@@ -3135,10 +3238,17 @@
 	if (brightness_mode > 3)
 		return -EINVAL;
 
+	tp_features.bright_16levels =
+			thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
+			brightness_check_levels();
+
 	b = brightness_get(NULL);
 	if (b < 0)
 		return 1;
 
+	if (tp_features.bright_16levels)
+		printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
+
 	ibm_backlight_device = backlight_device_register(
 					TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
 					&ibm_backlight_data);
@@ -3148,7 +3258,8 @@
 	}
 	vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
 
-	ibm_backlight_device->props.max_brightness = 7;
+	ibm_backlight_device->props.max_brightness =
+				(tp_features.bright_16levels)? 15 : 7;
 	ibm_backlight_device->props.brightness = b;
 	backlight_update_status(ibm_backlight_device);
 
@@ -3167,6 +3278,8 @@
 
 static int brightness_update_status(struct backlight_device *bd)
 {
+	/* it is the backlight class's job (caller) to handle
+	 * EINTR and other errors properly */
 	return brightness_set(
 		(bd->props.fb_blank == FB_BLANK_UNBLANK &&
 		 bd->props.power == FB_BLANK_UNBLANK) ?
@@ -3184,13 +3297,14 @@
 	if (brightness_mode & 1) {
 		if (!acpi_ec_read(brightness_offset, &lec))
 			return -EIO;
-		lec &= 7;
+		lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
 		level = lec;
 	};
 	if (brightness_mode & 2) {
 		lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
 			 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
 			>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+		lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
 		level = lcmos;
 	}
 
@@ -3206,12 +3320,13 @@
 	return level;
 }
 
+/* May return EINTR which can always be mapped to ERESTARTSYS */
 static int brightness_set(int value)
 {
 	int cmos_cmd, inc, i, res;
 	int current_value;
 
-	if (value > 7)
+	if (value > ((tp_features.bright_16levels)? 15 : 7))
 		return -EINVAL;
 
 	res = mutex_lock_interruptible(&brightness_mutex);
@@ -3227,7 +3342,7 @@
 	cmos_cmd = value > current_value ?
 			TP_CMOS_BRIGHTNESS_UP :
 			TP_CMOS_BRIGHTNESS_DOWN;
-	inc = value > current_value ? 1 : -1;
+	inc = (value > current_value)? 1 : -1;
 
 	res = 0;
 	for (i = current_value; i != value; i += inc) {
@@ -3256,10 +3371,11 @@
 	if ((level = brightness_get(NULL)) < 0) {
 		len += sprintf(p + len, "level:\t\tunreadable\n");
 	} else {
-		len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
+		len += sprintf(p + len, "level:\t\t%d\n", level);
 		len += sprintf(p + len, "commands:\tup, down\n");
 		len += sprintf(p + len, "commands:\tlevel <level>"
-			       " (<level> is 0-7)\n");
+			       " (<level> is 0-%d)\n",
+			       (tp_features.bright_16levels) ? 15 : 7);
 	}
 
 	return len;
@@ -3268,28 +3384,34 @@
 static int brightness_write(char *buf)
 {
 	int level;
-	int new_level;
+	int rc;
 	char *cmd;
+	int max_level = (tp_features.bright_16levels) ? 15 : 7;
+
+	level = brightness_get(NULL);
+	if (level < 0)
+		return level;
 
 	while ((cmd = next_cmd(&buf))) {
-		if ((level = brightness_get(NULL)) < 0)
-			return level;
-		level &= 7;
-
 		if (strlencmp(cmd, "up") == 0) {
-			new_level = level == 7 ? 7 : level + 1;
+			if (level < max_level)
+				level++;
 		} else if (strlencmp(cmd, "down") == 0) {
-			new_level = level == 0 ? 0 : level - 1;
-		} else if (sscanf(cmd, "level %d", &new_level) == 1 &&
-			   new_level >= 0 && new_level <= 7) {
-			/* new_level set */
+			if (level > 0)
+				level--;
+		} else if (sscanf(cmd, "level %d", &level) == 1 &&
+			   level >= 0 && level <= max_level) {
+			/* new level set */
 		} else
 			return -EINVAL;
-
-		brightness_set(new_level);
 	}
 
-	return 0;
+	/*
+	 * Now we know what the final level should be, so we try to set it.
+	 * Doing it this way makes the syscall restartable in case of EINTR
+	 */
+	rc = brightness_set(level);
+	return (rc == -EINTR)? ERESTARTSYS : rc;
 }
 
 static struct ibm_struct brightness_driver_data = {
@@ -3652,9 +3774,8 @@
 	/* scale down from 0-255 to 0-7 */
 	newlevel = (s >> 5) & 0x07;
 
-	rc = mutex_lock_interruptible(&fan_mutex);
-	if (rc < 0)
-		return rc;
+	if (mutex_lock_interruptible(&fan_mutex))
+		return -ERESTARTSYS;
 
 	rc = fan_get_status(&status);
 	if (!rc && (status &
@@ -3904,9 +4025,8 @@
 	int rc;
 	u8 s;
 
-	rc = mutex_lock_interruptible(&fan_mutex);
-	if (rc < 0)
-		return rc;
+	if (mutex_lock_interruptible(&fan_mutex))
+		return -ERESTARTSYS;
 	rc = fan_get_status(&s);
 	if (!rc)
 		fan_update_desired_level(s);
@@ -4040,9 +4160,8 @@
 	if (!fan_control_allowed)
 		return -EPERM;
 
-	rc = mutex_lock_interruptible(&fan_mutex);
-	if (rc < 0)
-		return rc;
+	if (mutex_lock_interruptible(&fan_mutex))
+		return -ERESTARTSYS;
 
 	if (level == TPACPI_FAN_LAST_LEVEL)
 		level = fan_control_desired_level;
@@ -4063,9 +4182,8 @@
 	if (!fan_control_allowed)
 		return -EPERM;
 
-	rc = mutex_lock_interruptible(&fan_mutex);
-	if (rc < 0)
-		return rc;
+	if (mutex_lock_interruptible(&fan_mutex))
+		return -ERESTARTSYS;
 
 	switch (fan_control_access_mode) {
 	case TPACPI_FAN_WR_ACPI_FANS:
@@ -4119,9 +4237,8 @@
 	if (!fan_control_allowed)
 		return -EPERM;
 
-	rc = mutex_lock_interruptible(&fan_mutex);
-	if (rc < 0)
-		return rc;
+	if (mutex_lock_interruptible(&fan_mutex))
+		return -ERESTARTSYS;
 
 	rc = 0;
 	switch (fan_control_access_mode) {
@@ -4158,9 +4275,8 @@
 	if (!fan_control_allowed)
 		return -EPERM;
 
-	rc = mutex_lock_interruptible(&fan_mutex);
-	if (rc < 0)
-		return rc;
+	if (mutex_lock_interruptible(&fan_mutex))
+		return -ERESTARTSYS;
 
 	rc = 0;
 	switch (fan_control_access_mode) {
@@ -4701,9 +4817,15 @@
 	unsigned int i;
 	struct ibm_struct *ibm;
 
+	if (!kp || !kp->name || !val)
+		return -EINVAL;
+
 	for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
 		ibm = ibms_init[i].data;
-		BUG_ON(ibm == NULL);
+		WARN_ON(ibm == NULL);
+
+		if (!ibm || !ibm->name)
+			continue;
 
 		if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
 			if (strlen(val) > sizeof(ibms_init[i].param) - 2)
@@ -4732,6 +4854,9 @@
 static int brightness_mode;
 module_param_named(brightness_mode, brightness_mode, int, 0);
 
+static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
+module_param(brightness_enable, uint, 0);
+
 static unsigned int hotkey_report_mode;
 module_param(hotkey_report_mode, uint, 0);
 
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 3abcc81..8fba2bb 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -84,7 +84,7 @@
 
 /* ThinkPad CMOS NVRAM constants */
 #define TP_NVRAM_ADDR_BRIGHTNESS       0x5e
-#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
+#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
 #define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
 
 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
@@ -246,6 +246,7 @@
 	u32 hotkey_wlsw:1;
 	u32 light:1;
 	u32 light_status:1;
+	u32 bright_16levels:1;
 	u32 wan:1;
 	u32 fan_ctrl_status_undef:1;
 	u32 input_device_registered:1;
@@ -338,6 +339,7 @@
 static struct backlight_device *ibm_backlight_device;
 static int brightness_offset = 0x31;
 static int brightness_mode;
+static unsigned int brightness_enable;	/* 0 = no, 1 = yes, 2 = auto */
 
 static int brightness_init(struct ibm_init_struct *iibm);
 static void brightness_exit(void);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index cd0a204..11adab1 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -75,6 +75,7 @@
 {
 	int i = 0;
 	int irq;
+	int p, t;
 
 	if (!valid_IRQ(gsi))
 		return;
@@ -85,15 +86,22 @@
 	if (i >= PNP_MAX_IRQ)
 		return;
 
-#ifdef CONFIG_X86
-	if (gsi < 16 && (triggering != ACPI_EDGE_SENSITIVE ||
-				polarity != ACPI_ACTIVE_HIGH)) {
-		pnp_warn("BIOS BUG: legacy PNP IRQ %d should be edge trigger, "
-				"active high", gsi);
-		triggering = ACPI_EDGE_SENSITIVE;
-		polarity = ACPI_ACTIVE_HIGH;
+	/*
+	 * in IO-APIC mode, use overrided attribute. Two reasons:
+	 * 1. BIOS bug in DSDT
+	 * 2. BIOS uses IO-APIC mode Interrupt Source Override
+	 */
+	if (!acpi_get_override_irq(gsi, &t, &p)) {
+		t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
+		p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
+
+		if (triggering != t || polarity != p) {
+			pnp_warn("IRQ %d override to %s, %s",
+				gsi, t ? "edge":"level", p ? "low":"high");
+			triggering = t;
+			polarity = p;
+		}
 	}
-#endif
 
 	res->irq_resource[i].flags = IORESOURCE_IRQ;	// Also clears _UNSET flag
 	res->irq_resource[i].flags |= irq_flags(triggering, polarity);
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 26d79f6..76411b1 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -78,7 +78,6 @@
 struct acpi_processor_power {
 	struct cpuidle_device dev;
 	struct acpi_processor_cx *state;
-	struct acpi_processor_cx *bm_state;
 	unsigned long bm_check_timestamp;
 	u32 default_state;
 	u32 bm_activity;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8ccedf7..e3c16c9 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -132,6 +132,11 @@
 int acpi_register_gsi (u32 gsi, int triggering, int polarity);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
+#ifdef CONFIG_X86_IO_APIC
+extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity);
+#else
+#define acpi_get_override_irq(bus, trigger, polarity) (-1)
+#endif
 /*
  * This function undoes the effect of one call to acpi_register_gsi().
  * If this matches the last registration, any IRQ resources for gsi
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 16a5154..c4e0016 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -92,6 +92,7 @@
 	struct kobject		kobj;
 	struct completion	kobj_unregister;
 	void			*governor_data;
+	struct cpuidle_state	*safe_state;
 };
 
 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);