--- /dev/null
+From b8e80cf386419453678b01bef830f53445ebb15d Mon Sep 17 00:00:00 2001
+From: Daniel T Chen <crimsun@ubuntu.com>
+Date: Tue, 30 Mar 2010 13:29:28 -0400
+Subject: ALSA: hda: Fix 0 dB offset for Lenovo Thinkpad models using AD1981
+
+From: Daniel T Chen <crimsun@ubuntu.com>
+
+commit b8e80cf386419453678b01bef830f53445ebb15d upstream.
+
+BugLink: https://launchpad.net/bugs/551606
+
+The OR's hardware distorts at PCM 100% because it does not correspond to
+0 dB. Fix this in patch_ad1981() for all models using the Thinkpad
+quirk.
+
+Reported-by: Jane Silber
+Signed-off-by: Daniel T Chen <crimsun@ubuntu.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/pci/hda/patch_analog.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sound/pci/hda/patch_analog.c
++++ b/sound/pci/hda/patch_analog.c
+@@ -1789,6 +1789,14 @@ static int patch_ad1981(struct hda_codec
+ case AD1981_THINKPAD:
+ spec->mixers[0] = ad1981_thinkpad_mixers;
+ spec->input_mux = &ad1981_thinkpad_capture_source;
++ /* set the upper-limit for mixer amp to 0dB for avoiding the
++ * possible damage by overloading
++ */
++ snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
++ (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
++ (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
++ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
++ (1 << AC_AMPCAP_MUTE_SHIFT));
+ break;
+ case AD1981_TOSHIBA:
+ spec->mixers[0] = ad1981_hp_mixers;
--- /dev/null
+From b0cc58a25d04160d39a80e436847eaa2fbc5aa09 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <error27@gmail.com>
+Date: Tue, 6 Apr 2010 19:31:26 +0300
+Subject: ALSA: mixart: range checking proc file
+
+From: Dan Carpenter <error27@gmail.com>
+
+commit b0cc58a25d04160d39a80e436847eaa2fbc5aa09 upstream.
+
+The original code doesn't take into consideration that the value of
+MIXART_BA0_SIZE - pos can be less than zero which would lead to a large
+unsigned value for "count".
+
+Also I moved the check that read size is a multiple of 4 bytes below
+the code that adjusts "count".
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/pci/mixart/mixart.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+--- a/sound/pci/mixart/mixart.c
++++ b/sound/pci/mixart/mixart.c
+@@ -1161,13 +1161,15 @@ static long snd_mixart_BA0_read(struct s
+ unsigned long count, unsigned long pos)
+ {
+ struct mixart_mgr *mgr = entry->private_data;
++ unsigned long maxsize;
+
+- count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
+- if(count <= 0)
++ if (pos >= MIXART_BA0_SIZE)
+ return 0;
+- if(pos + count > MIXART_BA0_SIZE)
+- count = (long)(MIXART_BA0_SIZE - pos);
+- if(copy_to_user_fromio(buf, MIXART_MEM( mgr, pos ), count))
++ maxsize = MIXART_BA0_SIZE - pos;
++ if (count > maxsize)
++ count = maxsize;
++ count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
++ if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count))
+ return -EFAULT;
+ return count;
+ }
+@@ -1180,13 +1182,15 @@ static long snd_mixart_BA1_read(struct s
+ unsigned long count, unsigned long pos)
+ {
+ struct mixart_mgr *mgr = entry->private_data;
++ unsigned long maxsize;
+
+- count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
+- if(count <= 0)
++ if (pos > MIXART_BA1_SIZE)
+ return 0;
+- if(pos + count > MIXART_BA1_SIZE)
+- count = (long)(MIXART_BA1_SIZE - pos);
+- if(copy_to_user_fromio(buf, MIXART_REG( mgr, pos ), count))
++ maxsize = MIXART_BA1_SIZE - pos;
++ if (count > maxsize)
++ count = maxsize;
++ count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
++ if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count))
+ return -EFAULT;
+ return count;
+ }
--- /dev/null
+From 36bc5ee6a8d13333980fa54e97d3469d3d4cda98 Mon Sep 17 00:00:00 2001
+From: Evan McClain <evan.mcclain@gatech.edu>
+Date: Tue, 9 Mar 2010 19:20:58 -0500
+Subject: backlight: mbp_nvidia_bl - add five more MacBook variants
+
+From: Evan McClain <evan.mcclain@gatech.edu>
+
+commit 36bc5ee6a8d13333980fa54e97d3469d3d4cda98 upstream.
+
+This adds the MacBook 1,1 2,1 3,1 4,1 and 4,2 to the DMI tables.
+
+Signed-off-by: Evan McClain <evan.mcclain@gatech.edu>
+Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/backlight/mbp_nvidia_bl.c | 45 ++++++++++++++++++++++++++++++++
+ 1 file changed, 45 insertions(+)
+
+--- a/drivers/video/backlight/mbp_nvidia_bl.c
++++ b/drivers/video/backlight/mbp_nvidia_bl.c
+@@ -139,6 +139,51 @@ static int mbp_dmi_match(const struct dm
+ static const struct dmi_system_id __initdata mbp_device_table[] = {
+ {
+ .callback = mbp_dmi_match,
++ .ident = "MacBook 1,1",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
++ },
++ .driver_data = (void *)&intel_chipset_data,
++ },
++ {
++ .callback = mbp_dmi_match,
++ .ident = "MacBook 2,1",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
++ },
++ .driver_data = (void *)&intel_chipset_data,
++ },
++ {
++ .callback = mbp_dmi_match,
++ .ident = "MacBook 3,1",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"),
++ },
++ .driver_data = (void *)&intel_chipset_data,
++ },
++ {
++ .callback = mbp_dmi_match,
++ .ident = "MacBook 4,1",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"),
++ },
++ .driver_data = (void *)&intel_chipset_data,
++ },
++ {
++ .callback = mbp_dmi_match,
++ .ident = "MacBook 4,2",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"),
++ },
++ .driver_data = (void *)&intel_chipset_data,
++ },
++ {
++ .callback = mbp_dmi_match,
+ .ident = "MacBookPro 3,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
--- /dev/null
+From: Corentin Chary <corentincj@iksaif.net>
+Date: Wed, 6 Jan 2010 22:07:40 +0100
+Subject: eeepc-laptop: add hotplug_disable parameter
+
+commit 322a1356be96bcc4b97e8e370f6468c821330077 upstream.
+
+Some new models need to disable wireless hotplug.
+For the moment, we don't know excactly what models need that,
+except 1005HA.
+Users will be able to use that param as a workaround.
+
+[bwh: Backported to 2.6.32]
+
+Signed-off-by: Corentin Chary <corentincj@iksaif.net>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/eeepc-laptop.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/platform/x86/eeepc-laptop.c
++++ b/drivers/platform/x86/eeepc-laptop.c
+@@ -254,6 +254,14 @@ MODULE_AUTHOR("Corentin Chary, Eric Coop
+ MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
+ MODULE_LICENSE("GPL");
+
++static bool hotplug_disabled;
++
++module_param(hotplug_disabled, bool, 0644);
++MODULE_PARM_DESC(hotplug_disabled,
++ "Disable hotplug for wireless device. "
++ "If your laptop need that, please report to "
++ "acpi4asus-user@lists.sourceforge.net.");
++
+ /*
+ * ACPI Helpers
+ */
+@@ -1305,6 +1313,8 @@ static int __devinit eeepc_hotk_add(stru
+ device->driver_data = ehotk;
+ ehotk->device = device;
+
++ ehotk->hotplug_disabled = hotplug_disabled;
++
+ eeepc_dmi_check();
+
+ result = eeepc_hotk_check();
--- /dev/null
+From: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+Date: Wed, 6 Jan 2010 22:07:37 +0100
+Subject: eeepc-laptop: disable cpu speed control on EeePC 701
+
+commit da8ba01deb98f3dc0558b1f5a37e64f40bba7904 upstream.
+
+The EeePC 4G ("701") implements CFVS, but it is not supported by the
+pre-installed OS, and the original option to change it in the BIOS
+setup screen was removed in later versions. Judging by the lack of
+"Super Hybrid Engine" on Asus product pages, this applies to all "701"
+models (4G/4G Surf/2G Surf).
+
+So Asus made a deliberate decision not to support it on this model.
+We have several reports that using it can cause the system to hang [1].
+That said, it does not happen all the time. Some users do not
+experience it at all (and apparently wish to continue "right-clocking").
+
+Check for the EeePC 701 using DMI. If met, then disable writes to the
+"cpufv" sysfs attribute and log an explanatory message.
+
+Add a "cpufv_disabled" attribute which allow users to override this
+policy. Writing to this attribute will log a second message.
+
+The sysfs attribute is more useful than a module option, because it
+makes it easier for userspace scripts to provide consistent behaviour
+(according to user configuration), regardless of whether the kernel
+includes this change.
+
+[1] <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=559578>
+
+[bwh: Backported to 2.6.32]
+
+Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+Signed-off-by: Corentin Chary <corentincj@iksaif.net>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/eeepc-laptop.c | 84 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 84 insertions(+)
+
+--- a/drivers/platform/x86/eeepc-laptop.c
++++ b/drivers/platform/x86/eeepc-laptop.c
+@@ -34,6 +34,7 @@
+ #include <linux/rfkill.h>
+ #include <linux/pci.h>
+ #include <linux/pci_hotplug.h>
++#include <linux/dmi.h>
+
+ #define EEEPC_LAPTOP_VERSION "0.1"
+
+@@ -135,6 +136,7 @@ struct eeepc_hotk {
+ acpi_handle handle; /* the handle of the hotk device */
+ u32 cm_supported; /* the control methods supported
+ by this BIOS */
++ bool cpufv_disabled;
+ uint init_flag; /* Init flags */
+ u16 event_count[128]; /* count for each event */
+ struct input_dev *inputdev;
+@@ -467,6 +469,8 @@ static ssize_t store_cpufv(struct device
+ struct eeepc_cpufv c;
+ int rv, value;
+
++ if (ehotk->cpufv_disabled)
++ return -EPERM;
+ if (get_cpufv(&c))
+ return -ENODEV;
+ rv = parse_arg(buf, count, &value);
+@@ -478,6 +482,38 @@ static ssize_t store_cpufv(struct device
+ return rv;
+ }
+
++static ssize_t show_cpufv_disabled(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ return sprintf(buf, "%d\n", ehotk->cpufv_disabled);
++}
++
++static ssize_t store_cpufv_disabled(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int rv, value;
++
++ rv = parse_arg(buf, count, &value);
++ if (rv < 0)
++ return rv;
++
++ switch (value) {
++ case 0:
++ if (ehotk->cpufv_disabled)
++ pr_warning("cpufv enabled (not officially supported "
++ "on this model)\n");
++ ehotk->cpufv_disabled = false;
++ return rv;
++ case 1:
++ return -EPERM;
++ default:
++ return -EINVAL;
++ }
++}
++
++
+ static struct device_attribute dev_attr_cpufv = {
+ .attr = {
+ .name = "cpufv",
+@@ -493,12 +529,22 @@ static struct device_attribute dev_attr_
+ .show = show_available_cpufv
+ };
+
++static struct device_attribute dev_attr_cpufv_disabled = {
++ .attr = {
++ .name = "cpufv_disabled",
++ .mode = 0644 },
++ .show = show_cpufv_disabled,
++ .store = store_cpufv_disabled
++};
++
++
+ static struct attribute *platform_attributes[] = {
+ &dev_attr_camera.attr,
+ &dev_attr_cardr.attr,
+ &dev_attr_disp.attr,
+ &dev_attr_cpufv.attr,
+ &dev_attr_available_cpufv.attr,
++ &dev_attr_cpufv_disabled.attr,
+ NULL
+ };
+
+@@ -564,6 +610,42 @@ static int eeepc_setkeycode(struct input
+ return -EINVAL;
+ }
+
++static void eeepc_dmi_check(void)
++{
++ const char *model;
++
++ /*
++ * Blacklist for setting cpufv (cpu speed).
++ *
++ * EeePC 4G ("701") implements CFVS, but it is not supported
++ * by the pre-installed OS, and the original option to change it
++ * in the BIOS setup screen was removed in later versions.
++ *
++ * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
++ * this applies to all "701" models (4G/4G Surf/2G Surf).
++ *
++ * So Asus made a deliberate decision not to support it on this model.
++ * We have several reports that using it can cause the system to hang
++ *
++ * The hang has also been reported on a "702" (Model name "8G"?).
++ *
++ * We avoid dmi_check_system() / dmi_match(), because they use
++ * substring matching. We don't want to affect the "701SD"
++ * and "701SDX" models, because they do support S.H.E.
++ */
++
++ model = dmi_get_system_info(DMI_PRODUCT_NAME);
++ if (!model)
++ return;
++
++ if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
++ ehotk->cpufv_disabled = true;
++ pr_info("model %s does not officially support setting cpu "
++ "speed\n", model);
++ pr_info("cpufv disabled to avoid instability\n");
++ }
++}
++
+ static void cmsg_quirk(int cm, const char *name)
+ {
+ int dummy;
+@@ -1208,6 +1290,8 @@ static int __devinit eeepc_hotk_add(stru
+ device->driver_data = ehotk;
+ ehotk->device = device;
+
++ eeepc_dmi_check();
++
+ result = eeepc_hotk_check();
+ if (result)
+ goto fail_platform_driver;
--- /dev/null
+From: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+Date: Sat, 20 Feb 2010 11:02:24 +0000
+Subject: eeepc-laptop: disable wireless hotplug for 1005PE
+
+commit ced69c59811f05b2f8378467cbb82ac6ed3c6a5a upstream.
+
+The wireless hotplug code is not needed on this model, and it disables
+the wired ethernet card. (Like on the 1005HA and 1201N).
+
+References: <http://lists.alioth.debian.org/pipermail/debian-eeepc-devel/2010-February/003281.html>
+
+[bwh: Backported to 2.6.32]
+
+Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+Reported-by: Ansgar Burchardt <ansgar@43-1.org>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/eeepc-laptop.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/platform/x86/eeepc-laptop.c
++++ b/drivers/platform/x86/eeepc-laptop.c
+@@ -660,7 +660,8 @@ static void eeepc_dmi_check(void)
+ * hotplug code. In fact, current hotplug code seems to unplug another
+ * device...
+ */
+- if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0) {
++ if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
++ strcmp(model, "1005PE") == 0) {
+ ehotk->hotplug_disabled = true;
+ pr_info("wlan hotplug disabled\n");
+ }
--- /dev/null
+From: Corentin Chary <corentincj@iksaif.net>
+Date: Wed, 6 Jan 2010 22:07:41 +0100
+Subject: eeepc-laptop: disable wireless hotplug for 1201N
+
+commit 4194e2f551a6308e6ab34ac88210bf54858aa7df upstream.
+
+[bwh: Backported to 2.6.32]
+
+Signed-off-by: Corentin Chary <corentincj@iksaif.net>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/eeepc-laptop.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/platform/x86/eeepc-laptop.c
++++ b/drivers/platform/x86/eeepc-laptop.c
+@@ -660,7 +660,7 @@ static void eeepc_dmi_check(void)
+ * hotplug code. In fact, current hotplug code seems to unplug another
+ * device...
+ */
+- if (strcmp(model, "1005HA") == 0) {
++ if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0) {
+ ehotk->hotplug_disabled = true;
+ pr_info("wlan hotplug disabled\n");
+ }
--- /dev/null
+From: Corentin Chary <corentincj@iksaif.net>
+Date: Wed, 6 Jan 2010 22:07:38 +0100
+Subject: eeepc-laptop: dmi blacklist to disable pci hotplug code
+
+commit 10ae4b5663ff3092553bfbd867e7bd474ce6c553 upstream.
+
+This is a short term workaround for Eeepc 1005HA.
+
+refs: <http://bugzilla.kernel.org/show_bug.cgi?id=14570>
+
+[bwh: Backported to 2.6.32]
+
+Signed-off-by: Corentin Chary <corentincj@iksaif.net>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/eeepc-laptop.c | 25 ++++++++++++++++++++-----
+ 1 file changed, 20 insertions(+), 5 deletions(-)
+
+--- a/drivers/platform/x86/eeepc-laptop.c
++++ b/drivers/platform/x86/eeepc-laptop.c
+@@ -137,6 +137,7 @@ struct eeepc_hotk {
+ u32 cm_supported; /* the control methods supported
+ by this BIOS */
+ bool cpufv_disabled;
++ bool hotplug_disabled;
+ uint init_flag; /* Init flags */
+ u16 event_count[128]; /* count for each event */
+ struct input_dev *inputdev;
+@@ -614,6 +615,10 @@ static void eeepc_dmi_check(void)
+ {
+ const char *model;
+
++ model = dmi_get_system_info(DMI_PRODUCT_NAME);
++ if (!model)
++ return;
++
+ /*
+ * Blacklist for setting cpufv (cpu speed).
+ *
+@@ -633,17 +638,24 @@ static void eeepc_dmi_check(void)
+ * substring matching. We don't want to affect the "701SD"
+ * and "701SDX" models, because they do support S.H.E.
+ */
+-
+- model = dmi_get_system_info(DMI_PRODUCT_NAME);
+- if (!model)
+- return;
+-
+ if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
+ ehotk->cpufv_disabled = true;
+ pr_info("model %s does not officially support setting cpu "
+ "speed\n", model);
+ pr_info("cpufv disabled to avoid instability\n");
+ }
++
++ /*
++ * Blacklist for wlan hotplug
++ *
++ * Eeepc 1005HA doesn't work like others models and don't need the
++ * hotplug code. In fact, current hotplug code seems to unplug another
++ * device...
++ */
++ if (strcmp(model, "1005HA") == 0) {
++ ehotk->hotplug_disabled = true;
++ pr_info("wlan hotplug disabled\n");
++ }
+ }
+
+ static void cmsg_quirk(int cm, const char *name)
+@@ -1177,6 +1189,9 @@ static int eeepc_rfkill_init(struct devi
+ if (result && result != -ENODEV)
+ goto exit;
+
++ if (ehotk->hotplug_disabled)
++ return 0;
++
+ result = eeepc_setup_pci_hotplug();
+ /*
+ * If we get -EBUSY then something else is handling the PCI hotplug -
--- /dev/null
+From b918397542388de75bd86c32fbfa820e5d629fa9 Mon Sep 17 00:00:00 2001
+From: Eric Sandeen <sandeen@redhat.com>
+Date: Mon, 16 Nov 2009 16:34:51 -0600
+Subject: ext3: Don't update the superblock in ext3_statfs()
+
+From: Eric Sandeen <sandeen@redhat.com>
+
+commit b918397542388de75bd86c32fbfa820e5d629fa9 upstream.
+
+commit a71ce8c6c9bf269b192f352ea555217815cf027e updated ext3_statfs()
+to update the on-disk superblock counters, but modified this buffer
+directly without any journaling of the change. This is one of the
+accesses that was causing the crc errors in journal replay as seen in
+kernel.org bugzilla #14354.
+
+The modifications were originally to keep the sb "more" in sync,
+so that a readonly fsck of the device didn't flag this as an
+error (as often), but apparently e2fsprogs deals with this differently
+now, anyway.
+
+Based on Ted's patch for ext4, which was in turn based on my
+work on that bug and another preliminary patch...
+
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/ext3/super.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/fs/ext3/super.c
++++ b/fs/ext3/super.c
+@@ -2686,13 +2686,11 @@ static int ext3_statfs (struct dentry *
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last;
+ buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter);
+- es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
+ buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
+ if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
+ buf->f_bavail = 0;
+ buf->f_files = le32_to_cpu(es->s_inodes_count);
+ buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter);
+- es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
+ buf->f_namelen = EXT3_NAME_LEN;
+ fsid = le64_to_cpup((void *)es->s_uuid) ^
+ le64_to_cpup((void *)es->s_uuid + sizeof(u64));
--- /dev/null
+From d965736b8cb42ae51ba9c3f13488035a98d025c6 Mon Sep 17 00:00:00 2001
+From: Eric Sandeen <sandeen@redhat.com>
+Date: Mon, 16 Nov 2009 16:27:30 -0600
+Subject: ext3: journal all modifications in ext3_xattr_set_handle
+
+From: Eric Sandeen <sandeen@redhat.com>
+
+commit d965736b8cb42ae51ba9c3f13488035a98d025c6 upstream.
+
+ext3_xattr_set_handle() was zeroing out an inode outside
+of journaling constraints; this is one of the accesses that
+was causing the crc errors in journal replay as seen in
+kernel.org bugzilla #14354.
+
+Although ext3 doesn't have the crc issue, modifications
+out of journal control are a Bad Thing.
+
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Signed-off-by: Jan Kara <jack@suse.cz>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/ext3/xattr.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/fs/ext3/xattr.c
++++ b/fs/ext3/xattr.c
+@@ -960,6 +960,10 @@ ext3_xattr_set_handle(handle_t *handle,
+ if (error)
+ goto cleanup;
+
++ error = ext3_journal_get_write_access(handle, is.iloc.bh);
++ if (error)
++ goto cleanup;
++
+ if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) {
+ struct ext3_inode *raw_inode = ext3_raw_inode(&is.iloc);
+ memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size);
+@@ -985,9 +989,6 @@ ext3_xattr_set_handle(handle_t *handle,
+ if (flags & XATTR_CREATE)
+ goto cleanup;
+ }
+- error = ext3_journal_get_write_access(handle, is.iloc.bh);
+- if (error)
+- goto cleanup;
+ if (!value) {
+ if (!is.s.not_found)
+ error = ext3_xattr_ibody_set(handle, inode, &i, &is);
--- /dev/null
+From d8e4ebf8b603bdcd091540e6b5bddf0dec10d516 Mon Sep 17 00:00:00 2001
+From: Jiri Kosina <jkosina@suse.cz>
+Date: Tue, 23 Mar 2010 16:32:37 +0100
+Subject: HID: fix oops in gyration_event()
+
+From: Jiri Kosina <jkosina@suse.cz>
+
+commit d8e4ebf8b603bdcd091540e6b5bddf0dec10d516 upstream.
+
+Fix oops caused by dereferencing field->hidinput in cases where
+the device hasn't been claimed by hid-input.
+
+Reported-by: Andreas Demmer <mail@andreas-demmer.de>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hid/hid-gyration.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/hid/hid-gyration.c
++++ b/drivers/hid/hid-gyration.c
+@@ -53,10 +53,13 @@ static int gyration_input_mapping(struct
+ static int gyration_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+ {
+- struct input_dev *input = field->hidinput->input;
++
++ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)
++ return 0;
+
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+ (usage->hid & 0xff) == 0x82) {
++ struct input_dev *input = field->hidinput->input;
+ input_event(input, usage->type, usage->code, 1);
+ input_sync(input);
+ input_event(input, usage->type, usage->code, 0);
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:44:22 2010
+From: Gleb Natapov <gleb@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:34 +0100
+Subject: KVM: Fix segment descriptor loading
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-7-git-send-email-stefan.bader@canonical.com>
+
+
+From: Gleb Natapov <gleb@redhat.com>
+
+commit c697518a861e6c43b92b848895f9926580ee63c3 upstream
+
+Add proper error and permission checking. This patch also change task
+switching code to load segment selectors before segment descriptors, like
+SDM requires, otherwise permission checking during segment descriptor
+loading will be incorrect.
+
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/include/asm/kvm_host.h | 3
+ arch/x86/kvm/emulate.c | 28 +-----
+ arch/x86/kvm/x86.c | 173 ++++++++++++++++++++++++++++++++++------
+ 3 files changed, 158 insertions(+), 46 deletions(-)
+
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -602,8 +602,7 @@ int emulator_set_dr(struct x86_emulate_c
+ unsigned long value);
+
+ void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
+-int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+- int type_bits, int seg);
++int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
+
+ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason);
+
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -1396,7 +1396,7 @@ static int emulate_ret_far(struct x86_em
+ rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
+ if (rc)
+ return rc;
+- rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, 1, VCPU_SREG_CS);
++ rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, VCPU_SREG_CS);
+ return rc;
+ }
+
+@@ -1992,12 +1992,11 @@ special_insn:
+ break;
+ case 0x8e: { /* mov seg, r/m16 */
+ uint16_t sel;
+- int type_bits;
+- int err;
+
+ sel = c->src.val;
+
+- if (c->modrm_reg == VCPU_SREG_CS) {
++ if (c->modrm_reg == VCPU_SREG_CS ||
++ c->modrm_reg > VCPU_SREG_GS) {
+ kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+ goto done;
+ }
+@@ -2005,18 +2004,7 @@ special_insn:
+ if (c->modrm_reg == VCPU_SREG_SS)
+ toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS);
+
+- if (c->modrm_reg <= 5) {
+- type_bits = (c->modrm_reg == 1) ? 9 : 1;
+- err = kvm_load_segment_descriptor(ctxt->vcpu, sel,
+- type_bits, c->modrm_reg);
+- } else {
+- printk(KERN_INFO "Invalid segreg in modrm byte 0x%02x\n",
+- c->modrm);
+- goto cannot_emulate;
+- }
+-
+- if (err < 0)
+- goto cannot_emulate;
++ rc = kvm_load_segment_descriptor(ctxt->vcpu, sel, c->modrm_reg);
+
+ c->dst.type = OP_NONE; /* Disable writeback. */
+ break;
+@@ -2186,11 +2174,9 @@ special_insn:
+ case 0xe9: /* jmp rel */
+ goto jmp;
+ case 0xea: /* jmp far */
+- if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val, 9,
+- VCPU_SREG_CS) < 0) {
+- DPRINTF("jmp far: Failed to load CS descriptor\n");
+- goto cannot_emulate;
+- }
++ if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val,
++ VCPU_SREG_CS))
++ goto done;
+
+ c->eip = c->src.val;
+ break;
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -4207,7 +4207,7 @@ static int kvm_load_realmode_segment(str
+ .unusable = 0,
+ };
+ kvm_x86_ops->set_segment(vcpu, &segvar, seg);
+- return 0;
++ return X86EMUL_CONTINUE;
+ }
+
+ static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
+@@ -4217,24 +4217,113 @@ static int is_vm86_segment(struct kvm_vc
+ (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_VM);
+ }
+
+-int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
+- int type_bits, int seg)
++int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg)
+ {
+ struct kvm_segment kvm_seg;
++ struct desc_struct seg_desc;
++ u8 dpl, rpl, cpl;
++ unsigned err_vec = GP_VECTOR;
++ u32 err_code = 0;
++ bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */
++ int ret;
+
+ if (is_vm86_segment(vcpu, seg) || !(vcpu->arch.cr0 & X86_CR0_PE))
+ return kvm_load_realmode_segment(vcpu, selector, seg);
+- if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg))
+- return 1;
+- kvm_seg.type |= type_bits;
+
+- if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS &&
+- seg != VCPU_SREG_LDTR)
+- if (!kvm_seg.s)
+- kvm_seg.unusable = 1;
+
++ /* NULL selector is not valid for TR, CS and SS */
++ if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR)
++ && null_selector)
++ goto exception;
++
++ /* TR should be in GDT only */
++ if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
++ goto exception;
++
++ ret = load_guest_segment_descriptor(vcpu, selector, &seg_desc);
++ if (ret)
++ return ret;
++
++ seg_desct_to_kvm_desct(&seg_desc, selector, &kvm_seg);
++
++ if (null_selector) { /* for NULL selector skip all following checks */
++ kvm_seg.unusable = 1;
++ goto load;
++ }
++
++ err_code = selector & 0xfffc;
++ err_vec = GP_VECTOR;
++
++ /* can't load system descriptor into segment selecor */
++ if (seg <= VCPU_SREG_GS && !kvm_seg.s)
++ goto exception;
++
++ if (!kvm_seg.present) {
++ err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
++ goto exception;
++ }
++
++ rpl = selector & 3;
++ dpl = kvm_seg.dpl;
++ cpl = kvm_x86_ops->get_cpl(vcpu);
++
++ switch (seg) {
++ case VCPU_SREG_SS:
++ /*
++ * segment is not a writable data segment or segment
++ * selector's RPL != CPL or segment selector's RPL != CPL
++ */
++ if (rpl != cpl || (kvm_seg.type & 0xa) != 0x2 || dpl != cpl)
++ goto exception;
++ break;
++ case VCPU_SREG_CS:
++ if (!(kvm_seg.type & 8))
++ goto exception;
++
++ if (kvm_seg.type & 4) {
++ /* conforming */
++ if (dpl > cpl)
++ goto exception;
++ } else {
++ /* nonconforming */
++ if (rpl > cpl || dpl != cpl)
++ goto exception;
++ }
++ /* CS(RPL) <- CPL */
++ selector = (selector & 0xfffc) | cpl;
++ break;
++ case VCPU_SREG_TR:
++ if (kvm_seg.s || (kvm_seg.type != 1 && kvm_seg.type != 9))
++ goto exception;
++ break;
++ case VCPU_SREG_LDTR:
++ if (kvm_seg.s || kvm_seg.type != 2)
++ goto exception;
++ break;
++ default: /* DS, ES, FS, or GS */
++ /*
++ * segment is not a data or readable code segment or
++ * ((segment is a data or nonconforming code segment)
++ * and (both RPL and CPL > DPL))
++ */
++ if ((kvm_seg.type & 0xa) == 0x8 ||
++ (((kvm_seg.type & 0xc) != 0xc) && (rpl > dpl && cpl > dpl)))
++ goto exception;
++ break;
++ }
++
++ if (!kvm_seg.unusable && kvm_seg.s) {
++ /* mark segment as accessed */
++ kvm_seg.type |= 1;
++ seg_desc.type |= 1;
++ save_guest_segment_descriptor(vcpu, selector, &seg_desc);
++ }
++load:
+ kvm_set_segment(vcpu, &kvm_seg, seg);
+- return 0;
++ return X86EMUL_CONTINUE;
++exception:
++ kvm_queue_exception_e(vcpu, err_vec, err_code);
++ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
+@@ -4260,6 +4349,14 @@ static void save_state_to_tss32(struct k
+ tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
+ }
+
++static void kvm_load_segment_selector(struct kvm_vcpu *vcpu, u16 sel, int seg)
++{
++ struct kvm_segment kvm_seg;
++ kvm_get_segment(vcpu, &kvm_seg, seg);
++ kvm_seg.selector = sel;
++ kvm_set_segment(vcpu, &kvm_seg, seg);
++}
++
+ static int load_state_from_tss32(struct kvm_vcpu *vcpu,
+ struct tss_segment_32 *tss)
+ {
+@@ -4277,25 +4374,41 @@ static int load_state_from_tss32(struct
+ kvm_register_write(vcpu, VCPU_REGS_RSI, tss->esi);
+ kvm_register_write(vcpu, VCPU_REGS_RDI, tss->edi);
+
+- if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR))
++ /*
++ * SDM says that segment selectors are loaded before segment
++ * descriptors
++ */
++ kvm_load_segment_selector(vcpu, tss->ldt_selector, VCPU_SREG_LDTR);
++ kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES);
++ kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS);
++ kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS);
++ kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS);
++ kvm_load_segment_selector(vcpu, tss->fs, VCPU_SREG_FS);
++ kvm_load_segment_selector(vcpu, tss->gs, VCPU_SREG_GS);
++
++ /*
++ * Now load segment descriptors. If fault happenes at this stage
++ * it is handled in a context of new task
++ */
++ if (kvm_load_segment_descriptor(vcpu, tss->ldt_selector, VCPU_SREG_LDTR))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
++ if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
++ if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
++ if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
++ if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS))
++ if (kvm_load_segment_descriptor(vcpu, tss->fs, VCPU_SREG_FS))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS))
++ if (kvm_load_segment_descriptor(vcpu, tss->gs, VCPU_SREG_GS))
+ return 1;
+ return 0;
+ }
+@@ -4336,19 +4449,33 @@ static int load_state_from_tss16(struct
+ kvm_register_write(vcpu, VCPU_REGS_RSI, tss->si);
+ kvm_register_write(vcpu, VCPU_REGS_RDI, tss->di);
+
+- if (kvm_load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR))
++ /*
++ * SDM says that segment selectors are loaded before segment
++ * descriptors
++ */
++ kvm_load_segment_selector(vcpu, tss->ldt, VCPU_SREG_LDTR);
++ kvm_load_segment_selector(vcpu, tss->es, VCPU_SREG_ES);
++ kvm_load_segment_selector(vcpu, tss->cs, VCPU_SREG_CS);
++ kvm_load_segment_selector(vcpu, tss->ss, VCPU_SREG_SS);
++ kvm_load_segment_selector(vcpu, tss->ds, VCPU_SREG_DS);
++
++ /*
++ * Now load segment descriptors. If fault happenes at this stage
++ * it is handled in a context of new task
++ */
++ if (kvm_load_segment_descriptor(vcpu, tss->ldt, VCPU_SREG_LDTR))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
++ if (kvm_load_segment_descriptor(vcpu, tss->es, VCPU_SREG_ES))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
++ if (kvm_load_segment_descriptor(vcpu, tss->cs, VCPU_SREG_CS))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
++ if (kvm_load_segment_descriptor(vcpu, tss->ss, VCPU_SREG_SS))
+ return 1;
+
+- if (kvm_load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
++ if (kvm_load_segment_descriptor(vcpu, tss->ds, VCPU_SREG_DS))
+ return 1;
+ return 0;
+ }
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:47:43 2010
+From: Eduardo Habkost <ehabkost@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:37 +0100
+Subject: KVM: SVM: Reset cr0 properly on vcpu reset
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-10-git-send-email-stefan.bader@canonical.com>
+
+
+From: Eduardo Habkost <ehabkost@redhat.com>
+
+commit 18fa000ae453767b59ab97477925895a3f0c46ea upstream
+
+svm_vcpu_reset() was not properly resetting the contents of the guest-visible
+cr0 register, causing the following issue:
+https://bugzilla.redhat.com/show_bug.cgi?id=525699
+
+Without resetting cr0 properly, the vcpu was running the SIPI bootstrap routine
+with paging enabled, making the vcpu get a pagefault exception while trying to
+run it.
+
+Instead of setting vmcb->save.cr0 directly, the new code just resets
+kvm->arch.cr0 and calls kvm_set_cr0(). The bits that were set/cleared on
+vmcb->save.cr0 (PG, WP, !CD, !NW) will be set properly by svm_set_cr0().
+
+kvm_set_cr0() is used instead of calling svm_set_cr0() directly to make sure
+kvm_mmu_reset_context() is called to reset the mmu to nonpaging mode.
+
+Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/kvm/svm.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/kvm/svm.c
++++ b/arch/x86/kvm/svm.c
+@@ -625,11 +625,12 @@ static void init_vmcb(struct vcpu_svm *s
+ save->rip = 0x0000fff0;
+ svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip;
+
+- /*
+- * cr0 val on cpu init should be 0x60000010, we enable cpu
+- * cache by default. the orderly way is to enable cache in bios.
++ /* This is the guest-visible cr0 value.
++ * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
+ */
+- save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
++ svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
++ kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
++
+ save->cr4 = X86_CR4_PAE;
+ /* rdx = ?? */
+
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:48:04 2010
+From: Sheng Yang <sheng@linux.intel.com>
+Date: Fri, 19 Mar 2010 15:47:38 +0100
+Subject: KVM: VMX: Disable unrestricted guest when EPT disabled
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-11-git-send-email-stefan.bader@canonical.com>
+
+
+From: Sheng Yang <sheng@linux.intel.com>
+
+commit 046d87103addc117f0d397196e85189722d4d7de upstream
+
+Otherwise would cause VMEntry failure when using ept=0 on unrestricted guest
+supported processors.
+
+Signed-off-by: Sheng Yang <sheng@linux.intel.com>
+Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/kvm/vmx.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -2302,8 +2302,10 @@ static int vmx_vcpu_setup(struct vcpu_vm
+ ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+ if (vmx->vpid == 0)
+ exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
+- if (!enable_ept)
++ if (!enable_ept) {
+ exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
++ enable_unrestricted_guest = 0;
++ }
+ if (!enable_unrestricted_guest)
+ exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
+ vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:44:45 2010
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Fri, 19 Mar 2010 15:47:35 +0100
+Subject: KVM: VMX: Update instruction length on intercepted BP
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-8-git-send-email-stefan.bader@canonical.com>
+
+
+From: Jan Kiszka <jan.kiszka@siemens.com>
+
+commit c573cd22939e54fc1b8e672054a505048987a7cb upstream
+
+We intercept #BP while in guest debugging mode. As VM exits due to
+intercepted exceptions do not necessarily come with valid
+idt_vectoring, we have to update event_exit_inst_len explicitly in such
+cases. At least in the absence of migration, this ensures that
+re-injections of #BP will find and use the correct instruction length.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/kvm/vmx.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -2674,6 +2674,12 @@ static int handle_rmode_exception(struct
+ kvm_queue_exception(vcpu, vec);
+ return 1;
+ case BP_VECTOR:
++ /*
++ * Update instruction length as we may reinject the exception
++ * from user space while in guest debugging mode.
++ */
++ to_vmx(vcpu)->vcpu.arch.event_exit_inst_len =
++ vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
+ return 0;
+ /* fall through */
+@@ -2790,6 +2796,13 @@ static int handle_exception(struct kvm_v
+ kvm_run->debug.arch.dr7 = vmcs_readl(GUEST_DR7);
+ /* fall through */
+ case BP_VECTOR:
++ /*
++ * Update instruction length as we may reinject #BP from
++ * user space while in guest debugging mode. Reading it for
++ * #DB as well causes no harm, it is not used in that case.
++ */
++ vmx->vcpu.arch.event_exit_inst_len =
++ vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ kvm_run->exit_reason = KVM_EXIT_DEBUG;
+ kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
+ kvm_run->debug.arch.exception = ex_no;
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:47:24 2010
+From: Eduardo Habkost <ehabkost@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:36 +0100
+Subject: KVM: VMX: Use macros instead of hex value on cr0 initialization
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-9-git-send-email-stefan.bader@canonical.com>
+
+
+From: Eduardo Habkost <ehabkost@redhat.com>
+
+commit fa40052ca04bdbbeb20b839cc8ffe9fa7beefbe9 upstream
+
+This should have no effect, it is just to make the code clearer.
+
+Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/kvm/vmx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -2510,7 +2510,7 @@ static int vmx_vcpu_reset(struct kvm_vcp
+ if (vmx->vpid != 0)
+ vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
+
+- vmx->vcpu.arch.cr0 = 0x60000010;
++ vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
+ vmx_set_cr0(&vmx->vcpu, vmx->vcpu.arch.cr0); /* enter rmode */
+ vmx_set_cr4(&vmx->vcpu, 0);
+ vmx_set_efer(&vmx->vcpu, 0);
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:48:33 2010
+From: Marcelo Tosatti <mtosatti@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:39 +0100
+Subject: KVM: x86: disable paravirt mmu reporting
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-12-git-send-email-stefan.bader@canonical.com>
+
+
+From: Marcelo Tosatti <mtosatti@redhat.com>
+
+commit a68a6a7282373bedba8a2ed751b6384edb983a64 upstream
+
+Disable paravirt MMU capability reporting, so that new (or rebooted)
+guests switch to native operation.
+
+Paravirt MMU is a burden to maintain and does not bring significant
+advantages compared to shadow anymore.
+
+Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/kvm/x86.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -1242,8 +1242,8 @@ int kvm_dev_ioctl_check_extension(long e
+ case KVM_CAP_NR_MEMSLOTS:
+ r = KVM_MEMORY_SLOTS;
+ break;
+- case KVM_CAP_PV_MMU:
+- r = !tdp_enabled;
++ case KVM_CAP_PV_MMU: /* obsolete */
++ r = 0;
+ break;
+ case KVM_CAP_IOMMU:
+ r = iommu_found();
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:41:50 2010
+From: Gleb Natapov <gleb@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:30 +0100
+Subject: KVM: x86 emulator: Add Virtual-8086 mode of emulation
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-3-git-send-email-stefan.bader@canonical.com>
+
+
+From: Gleb Natapov <gleb@redhat.com>
+
+commit a0044755679f3e761b8b95995e5f2db2b7efd0f6 upstream
+
+For some instructions CPU behaves differently for real-mode and
+virtual 8086. Let emulator know which mode cpu is in, so it will
+not poke into vcpu state directly.
+
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/include/asm/kvm_emulate.h | 1 +
+ arch/x86/kvm/emulate.c | 14 +++++++-------
+ arch/x86/kvm/x86.c | 3 ++-
+ 3 files changed, 10 insertions(+), 8 deletions(-)
+
+--- a/arch/x86/include/asm/kvm_emulate.h
++++ b/arch/x86/include/asm/kvm_emulate.h
+@@ -168,6 +168,7 @@ struct x86_emulate_ctxt {
+
+ /* Execution mode, passed to the emulator. */
+ #define X86EMUL_MODE_REAL 0 /* Real mode. */
++#define X86EMUL_MODE_VM86 1 /* Virtual 8086 mode. */
+ #define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */
+ #define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */
+ #define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -895,6 +895,7 @@ x86_decode_insn(struct x86_emulate_ctxt
+
+ switch (mode) {
+ case X86EMUL_MODE_REAL:
++ case X86EMUL_MODE_VM86:
+ case X86EMUL_MODE_PROT16:
+ def_op_bytes = def_ad_bytes = 2;
+ break;
+@@ -1453,7 +1454,7 @@ emulate_syscall(struct x86_emulate_ctxt
+
+ /* syscall is not available in real mode */
+ if (c->lock_prefix || ctxt->mode == X86EMUL_MODE_REAL
+- || !(ctxt->vcpu->arch.cr0 & X86_CR0_PE))
++ || ctxt->mode == X86EMUL_MODE_VM86)
+ return -1;
+
+ setup_syscalls_segments(ctxt, &cs, &ss);
+@@ -1505,9 +1506,8 @@ emulate_sysenter(struct x86_emulate_ctxt
+ if (c->lock_prefix)
+ return -1;
+
+- /* inject #GP if in real mode or paging is disabled */
+- if (ctxt->mode == X86EMUL_MODE_REAL ||
+- !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
++ /* inject #GP if in real mode */
++ if (ctxt->mode == X86EMUL_MODE_REAL) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+@@ -1571,9 +1571,9 @@ emulate_sysexit(struct x86_emulate_ctxt
+ if (c->lock_prefix)
+ return -1;
+
+- /* inject #GP if in real mode or paging is disabled */
+- if (ctxt->mode == X86EMUL_MODE_REAL
+- || !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
++ /* inject #GP if in real mode or Virtual 8086 mode */
++ if (ctxt->mode == X86EMUL_MODE_REAL ||
++ ctxt->mode == X86EMUL_MODE_VM86) {
+ kvm_inject_gp(ctxt->vcpu, 0);
+ return -1;
+ }
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -2828,8 +2828,9 @@ int emulate_instruction(struct kvm_vcpu
+ vcpu->arch.emulate_ctxt.vcpu = vcpu;
+ vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+ vcpu->arch.emulate_ctxt.mode =
++ (!(vcpu->arch.cr0 & X86_CR0_PE)) ? X86EMUL_MODE_REAL :
+ (vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
+- ? X86EMUL_MODE_REAL : cs_l
++ ? X86EMUL_MODE_VM86 : cs_l
+ ? X86EMUL_MODE_PROT64 : cs_db
+ ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:42:27 2010
+From: Gleb Natapov <gleb@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:32 +0100
+Subject: KVM: x86 emulator: Check IOPL level during io instruction emulation
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-5-git-send-email-stefan.bader@canonical.com>
+
+
+From: Gleb Natapov <gleb@redhat.com>
+
+commit f850e2e603bf5a05b0aee7901857cf85715aa694 upstream
+
+Make emulator check that vcpu is allowed to execute IN, INS, OUT,
+OUTS, CLI, STI.
+
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/include/asm/kvm_host.h | 1
+ arch/x86/kvm/emulate.c | 89 ++++++++++++++++++++++++++++++++++++----
+ arch/x86/kvm/x86.c | 10 +---
+ 3 files changed, 87 insertions(+), 13 deletions(-)
+
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -663,6 +663,7 @@ void kvm_disable_tdp(void);
+
+ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
+ int complete_pio(struct kvm_vcpu *vcpu);
++bool kvm_check_iopl(struct kvm_vcpu *vcpu);
+
+ struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn);
+
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -1620,6 +1620,57 @@ emulate_sysexit(struct x86_emulate_ctxt
+ return 0;
+ }
+
++static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
++{
++ int iopl;
++ if (ctxt->mode == X86EMUL_MODE_REAL)
++ return false;
++ if (ctxt->mode == X86EMUL_MODE_VM86)
++ return true;
++ iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
++ return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl;
++}
++
++static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
++ struct x86_emulate_ops *ops,
++ u16 port, u16 len)
++{
++ struct kvm_segment tr_seg;
++ int r;
++ u16 io_bitmap_ptr;
++ u8 perm, bit_idx = port & 0x7;
++ unsigned mask = (1 << len) - 1;
++
++ kvm_get_segment(ctxt->vcpu, &tr_seg, VCPU_SREG_TR);
++ if (tr_seg.unusable)
++ return false;
++ if (tr_seg.limit < 103)
++ return false;
++ r = ops->read_std(tr_seg.base + 102, &io_bitmap_ptr, 2, ctxt->vcpu,
++ NULL);
++ if (r != X86EMUL_CONTINUE)
++ return false;
++ if (io_bitmap_ptr + port/8 > tr_seg.limit)
++ return false;
++ r = ops->read_std(tr_seg.base + io_bitmap_ptr + port/8, &perm, 1,
++ ctxt->vcpu, NULL);
++ if (r != X86EMUL_CONTINUE)
++ return false;
++ if ((perm >> bit_idx) & mask)
++ return false;
++ return true;
++}
++
++static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
++ struct x86_emulate_ops *ops,
++ u16 port, u16 len)
++{
++ if (emulator_bad_iopl(ctxt))
++ if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
++ return false;
++ return true;
++}
++
+ int
+ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+ {
+@@ -1779,7 +1830,12 @@ special_insn:
+ break;
+ case 0x6c: /* insb */
+ case 0x6d: /* insw/insd */
+- if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
++ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
++ (c->d & ByteOp) ? 1 : c->op_bytes)) {
++ kvm_inject_gp(ctxt->vcpu, 0);
++ goto done;
++ }
++ if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ 1,
+ (c->d & ByteOp) ? 1 : c->op_bytes,
+ c->rep_prefix ?
+@@ -1795,6 +1851,11 @@ special_insn:
+ return 0;
+ case 0x6e: /* outsb */
+ case 0x6f: /* outsw/outsd */
++ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
++ (c->d & ByteOp) ? 1 : c->op_bytes)) {
++ kvm_inject_gp(ctxt->vcpu, 0);
++ goto done;
++ }
+ if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ 0,
+ (c->d & ByteOp) ? 1 : c->op_bytes,
+@@ -2094,7 +2155,13 @@ special_insn:
+ case 0xef: /* out (e/r)ax,dx */
+ port = c->regs[VCPU_REGS_RDX];
+ io_dir_in = 0;
+- do_io: if (kvm_emulate_pio(ctxt->vcpu, NULL, io_dir_in,
++ do_io:
++ if (!emulator_io_permited(ctxt, ops, port,
++ (c->d & ByteOp) ? 1 : c->op_bytes)) {
++ kvm_inject_gp(ctxt->vcpu, 0);
++ goto done;
++ }
++ if (kvm_emulate_pio(ctxt->vcpu, NULL, io_dir_in,
+ (c->d & ByteOp) ? 1 : c->op_bytes,
+ port) != 0) {
+ c->eip = saved_eip;
+@@ -2119,13 +2186,21 @@ special_insn:
+ c->dst.type = OP_NONE; /* Disable writeback. */
+ break;
+ case 0xfa: /* cli */
+- ctxt->eflags &= ~X86_EFLAGS_IF;
+- c->dst.type = OP_NONE; /* Disable writeback. */
++ if (emulator_bad_iopl(ctxt))
++ kvm_inject_gp(ctxt->vcpu, 0);
++ else {
++ ctxt->eflags &= ~X86_EFLAGS_IF;
++ c->dst.type = OP_NONE; /* Disable writeback. */
++ }
+ break;
+ case 0xfb: /* sti */
+- toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
+- ctxt->eflags |= X86_EFLAGS_IF;
+- c->dst.type = OP_NONE; /* Disable writeback. */
++ if (emulator_bad_iopl(ctxt))
++ kvm_inject_gp(ctxt->vcpu, 0);
++ else {
++ toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
++ ctxt->eflags |= X86_EFLAGS_IF;
++ c->dst.type = OP_NONE; /* Disable writeback. */
++ }
+ break;
+ case 0xfc: /* cld */
+ ctxt->eflags &= ~EFLG_DF;
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -3079,6 +3079,8 @@ int kvm_emulate_pio(struct kvm_vcpu *vcp
+ {
+ unsigned long val;
+
++ trace_kvm_pio(!in, port, size, 1);
++
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+ vcpu->run->io.size = vcpu->arch.pio.size = size;
+@@ -3090,9 +3092,6 @@ int kvm_emulate_pio(struct kvm_vcpu *vcp
+ vcpu->arch.pio.down = 0;
+ vcpu->arch.pio.rep = 0;
+
+- trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port,
+- size, 1);
+-
+ val = kvm_register_read(vcpu, VCPU_REGS_RAX);
+ memcpy(vcpu->arch.pio_data, &val, 4);
+
+@@ -3111,6 +3110,8 @@ int kvm_emulate_pio_string(struct kvm_vc
+ unsigned now, in_page;
+ int ret = 0;
+
++ trace_kvm_pio(!in, port, size, count);
++
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+ vcpu->run->io.size = vcpu->arch.pio.size = size;
+@@ -3122,9 +3123,6 @@ int kvm_emulate_pio_string(struct kvm_vc
+ vcpu->arch.pio.down = down;
+ vcpu->arch.pio.rep = rep;
+
+- trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port,
+- size, count);
+-
+ if (!count) {
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
+ return 1;
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:42:11 2010
+From: Gleb Natapov <gleb@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:31 +0100
+Subject: KVM: x86 emulator: fix memory access during x86 emulation
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-4-git-send-email-stefan.bader@canonical.com>
+
+
+From: Gleb Natapov <gleb@redhat.com>
+
+commit 1871c6020d7308afb99127bba51f04548e7ca84e upstream
+
+Currently when x86 emulator needs to access memory, page walk is done with
+broadest permission possible, so if emulated instruction was executed
+by userspace process it can still access kernel memory. Fix that by
+providing correct memory access to page walker during emulation.
+
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/include/asm/kvm_emulate.h | 14 +++
+ arch/x86/include/asm/kvm_host.h | 7 +
+ arch/x86/kvm/emulate.c | 6 -
+ arch/x86/kvm/mmu.c | 17 +---
+ arch/x86/kvm/mmu.h | 6 +
+ arch/x86/kvm/paging_tmpl.h | 11 ++-
+ arch/x86/kvm/x86.c | 131 ++++++++++++++++++++++++++++---------
+ 7 files changed, 142 insertions(+), 50 deletions(-)
+
+--- a/arch/x86/include/asm/kvm_emulate.h
++++ b/arch/x86/include/asm/kvm_emulate.h
+@@ -54,13 +54,23 @@ struct x86_emulate_ctxt;
+ struct x86_emulate_ops {
+ /*
+ * read_std: Read bytes of standard (non-emulated/special) memory.
+- * Used for instruction fetch, stack operations, and others.
++ * Used for descriptor reading.
+ * @addr: [IN ] Linear address from which to read.
+ * @val: [OUT] Value read from memory, zero-extended to 'u_long'.
+ * @bytes: [IN ] Number of bytes to read from memory.
+ */
+ int (*read_std)(unsigned long addr, void *val,
+- unsigned int bytes, struct kvm_vcpu *vcpu);
++ unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error);
++
++ /*
++ * fetch: Read bytes of standard (non-emulated/special) memory.
++ * Used for instruction fetch.
++ * @addr: [IN ] Linear address from which to read.
++ * @val: [OUT] Value read from memory, zero-extended to 'u_long'.
++ * @bytes: [IN ] Number of bytes to read from memory.
++ */
++ int (*fetch)(unsigned long addr, void *val,
++ unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error);
+
+ /*
+ * read_emulated: Read bytes from emulated/special memory area.
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -256,7 +256,8 @@ struct kvm_mmu {
+ void (*new_cr3)(struct kvm_vcpu *vcpu);
+ int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+ void (*free)(struct kvm_vcpu *vcpu);
+- gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva);
++ gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access,
++ u32 *error);
+ void (*prefetch_page)(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page);
+ int (*sync_page)(struct kvm_vcpu *vcpu,
+@@ -645,6 +646,10 @@ void __kvm_mmu_free_some_pages(struct kv
+ int kvm_mmu_load(struct kvm_vcpu *vcpu);
+ void kvm_mmu_unload(struct kvm_vcpu *vcpu);
+ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu);
++gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error);
++gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva, u32 *error);
++gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u32 *error);
++gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, u32 *error);
+
+ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
+
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -612,7 +612,7 @@ static int do_fetch_insn_byte(struct x86
+
+ if (linear < fc->start || linear >= fc->end) {
+ size = min(15UL, PAGE_SIZE - offset_in_page(linear));
+- rc = ops->read_std(linear, fc->data, size, ctxt->vcpu);
++ rc = ops->fetch(linear, fc->data, size, ctxt->vcpu, NULL);
+ if (rc)
+ return rc;
+ fc->start = linear;
+@@ -667,11 +667,11 @@ static int read_descriptor(struct x86_em
+ op_bytes = 3;
+ *address = 0;
+ rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
+- ctxt->vcpu);
++ ctxt->vcpu, NULL);
+ if (rc)
+ return rc;
+ rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
+- ctxt->vcpu);
++ ctxt->vcpu, NULL);
+ return rc;
+ }
+
+--- a/arch/x86/kvm/mmu.c
++++ b/arch/x86/kvm/mmu.c
+@@ -136,12 +136,6 @@ module_param(oos_shadow, bool, 0644);
+ #define PT64_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK \
+ | PT64_NX_MASK)
+
+-#define PFERR_PRESENT_MASK (1U << 0)
+-#define PFERR_WRITE_MASK (1U << 1)
+-#define PFERR_USER_MASK (1U << 2)
+-#define PFERR_RSVD_MASK (1U << 3)
+-#define PFERR_FETCH_MASK (1U << 4)
+-
+ #define PT_PDPE_LEVEL 3
+ #define PT_DIRECTORY_LEVEL 2
+ #define PT_PAGE_TABLE_LEVEL 1
+@@ -1639,7 +1633,7 @@ struct page *gva_to_page(struct kvm_vcpu
+ {
+ struct page *page;
+
+- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva);
++ gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL);
+
+ if (gpa == UNMAPPED_GVA)
+ return NULL;
+@@ -2162,8 +2156,11 @@ void kvm_mmu_sync_roots(struct kvm_vcpu
+ spin_unlock(&vcpu->kvm->mmu_lock);
+ }
+
+-static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr)
++static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr,
++ u32 access, u32 *error)
+ {
++ if (error)
++ *error = 0;
+ return vaddr;
+ }
+
+@@ -2747,7 +2744,7 @@ int kvm_mmu_unprotect_page_virt(struct k
+ if (tdp_enabled)
+ return 0;
+
+- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, gva);
++ gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL);
+
+ spin_lock(&vcpu->kvm->mmu_lock);
+ r = kvm_mmu_unprotect_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+@@ -3245,7 +3242,7 @@ static void audit_mappings_page(struct k
+ if (is_shadow_present_pte(ent) && !is_last_spte(ent, level))
+ audit_mappings_page(vcpu, ent, va, level - 1);
+ else {
+- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, va);
++ gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, va, NULL);
+ gfn_t gfn = gpa >> PAGE_SHIFT;
+ pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn);
+ hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT;
+--- a/arch/x86/kvm/mmu.h
++++ b/arch/x86/kvm/mmu.h
+@@ -37,6 +37,12 @@
+ #define PT32_ROOT_LEVEL 2
+ #define PT32E_ROOT_LEVEL 3
+
++#define PFERR_PRESENT_MASK (1U << 0)
++#define PFERR_WRITE_MASK (1U << 1)
++#define PFERR_USER_MASK (1U << 2)
++#define PFERR_RSVD_MASK (1U << 3)
++#define PFERR_FETCH_MASK (1U << 4)
++
+ int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
+
+ static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+--- a/arch/x86/kvm/paging_tmpl.h
++++ b/arch/x86/kvm/paging_tmpl.h
+@@ -491,18 +491,23 @@ static void FNAME(invlpg)(struct kvm_vcp
+ spin_unlock(&vcpu->kvm->mmu_lock);
+ }
+
+-static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
++static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access,
++ u32 *error)
+ {
+ struct guest_walker walker;
+ gpa_t gpa = UNMAPPED_GVA;
+ int r;
+
+- r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0);
++ r = FNAME(walk_addr)(&walker, vcpu, vaddr,
++ !!(access & PFERR_WRITE_MASK),
++ !!(access & PFERR_USER_MASK),
++ !!(access & PFERR_FETCH_MASK));
+
+ if (r) {
+ gpa = gfn_to_gpa(walker.gfn);
+ gpa |= vaddr & ~PAGE_MASK;
+- }
++ } else if (error)
++ *error = walker.error_code;
+
+ return gpa;
+ }
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -2505,14 +2505,41 @@ static int vcpu_mmio_read(struct kvm_vcp
+ return kvm_io_bus_read(&vcpu->kvm->mmio_bus, addr, len, v);
+ }
+
+-static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
+- struct kvm_vcpu *vcpu)
++gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
++{
++ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
++ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
++}
++
++ gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
++{
++ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
++ access |= PFERR_FETCH_MASK;
++ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
++}
++
++gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
++{
++ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
++ access |= PFERR_WRITE_MASK;
++ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
++}
++
++/* uses this to access any guest's mapped memory without checking CPL */
++gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
++{
++ return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, 0, error);
++}
++
++static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
++ struct kvm_vcpu *vcpu, u32 access,
++ u32 *error)
+ {
+ void *data = val;
+ int r = X86EMUL_CONTINUE;
+
+ while (bytes) {
+- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
++ gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
+ unsigned offset = addr & (PAGE_SIZE-1);
+ unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset);
+ int ret;
+@@ -2535,14 +2562,37 @@ out:
+ return r;
+ }
+
++/* used for instruction fetching */
++static int kvm_fetch_guest_virt(gva_t addr, void *val, unsigned int bytes,
++ struct kvm_vcpu *vcpu, u32 *error)
++{
++ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
++ return kvm_read_guest_virt_helper(addr, val, bytes, vcpu,
++ access | PFERR_FETCH_MASK, error);
++}
++
++static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
++ struct kvm_vcpu *vcpu, u32 *error)
++{
++ u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
++ return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
++ error);
++}
++
++static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
++ struct kvm_vcpu *vcpu, u32 *error)
++{
++ return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
++}
++
+ static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
+- struct kvm_vcpu *vcpu)
++ struct kvm_vcpu *vcpu, u32 *error)
+ {
+ void *data = val;
+ int r = X86EMUL_CONTINUE;
+
+ while (bytes) {
+- gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
++ gpa_t gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error);
+ unsigned offset = addr & (PAGE_SIZE-1);
+ unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
+ int ret;
+@@ -2572,6 +2622,7 @@ static int emulator_read_emulated(unsign
+ struct kvm_vcpu *vcpu)
+ {
+ gpa_t gpa;
++ u32 error_code;
+
+ if (vcpu->mmio_read_completed) {
+ memcpy(val, vcpu->mmio_data, bytes);
+@@ -2581,17 +2632,20 @@ static int emulator_read_emulated(unsign
+ return X86EMUL_CONTINUE;
+ }
+
+- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
++ gpa = kvm_mmu_gva_to_gpa_read(vcpu, addr, &error_code);
++
++ if (gpa == UNMAPPED_GVA) {
++ kvm_inject_page_fault(vcpu, addr, error_code);
++ return X86EMUL_PROPAGATE_FAULT;
++ }
+
+ /* For APIC access vmexit */
+ if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
+ goto mmio;
+
+- if (kvm_read_guest_virt(addr, val, bytes, vcpu)
++ if (kvm_read_guest_virt(addr, val, bytes, vcpu, NULL)
+ == X86EMUL_CONTINUE)
+ return X86EMUL_CONTINUE;
+- if (gpa == UNMAPPED_GVA)
+- return X86EMUL_PROPAGATE_FAULT;
+
+ mmio:
+ /*
+@@ -2630,11 +2684,12 @@ static int emulator_write_emulated_onepa
+ struct kvm_vcpu *vcpu)
+ {
+ gpa_t gpa;
++ u32 error_code;
+
+- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
++ gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, &error_code);
+
+ if (gpa == UNMAPPED_GVA) {
+- kvm_inject_page_fault(vcpu, addr, 2);
++ kvm_inject_page_fault(vcpu, addr, error_code);
+ return X86EMUL_PROPAGATE_FAULT;
+ }
+
+@@ -2698,7 +2753,7 @@ static int emulator_cmpxchg_emulated(uns
+ char *kaddr;
+ u64 val;
+
+- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
++ gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);
+
+ if (gpa == UNMAPPED_GVA ||
+ (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
+@@ -2777,7 +2832,7 @@ void kvm_report_emulation_failure(struct
+
+ rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
+
+- kvm_read_guest_virt(rip_linear, (void *)opcodes, 4, vcpu);
++ kvm_read_guest_virt(rip_linear, (void *)opcodes, 4, vcpu, NULL);
+
+ printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
+ context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+@@ -2785,7 +2840,8 @@ void kvm_report_emulation_failure(struct
+ EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
+
+ static struct x86_emulate_ops emulate_ops = {
+- .read_std = kvm_read_guest_virt,
++ .read_std = kvm_read_guest_virt_system,
++ .fetch = kvm_fetch_guest_virt,
+ .read_emulated = emulator_read_emulated,
+ .write_emulated = emulator_write_emulated,
+ .cmpxchg_emulated = emulator_cmpxchg_emulated,
+@@ -2922,12 +2978,17 @@ static int pio_copy_data(struct kvm_vcpu
+ gva_t q = vcpu->arch.pio.guest_gva;
+ unsigned bytes;
+ int ret;
++ u32 error_code;
+
+ bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
+ if (vcpu->arch.pio.in)
+- ret = kvm_write_guest_virt(q, p, bytes, vcpu);
++ ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code);
+ else
+- ret = kvm_read_guest_virt(q, p, bytes, vcpu);
++ ret = kvm_read_guest_virt(q, p, bytes, vcpu, &error_code);
++
++ if (ret == X86EMUL_PROPAGATE_FAULT)
++ kvm_inject_page_fault(vcpu, q, error_code);
++
+ return ret;
+ }
+
+@@ -2948,7 +3009,7 @@ int complete_pio(struct kvm_vcpu *vcpu)
+ if (io->in) {
+ r = pio_copy_data(vcpu);
+ if (r)
+- return r;
++ goto out;
+ }
+
+ delta = 1;
+@@ -2975,7 +3036,7 @@ int complete_pio(struct kvm_vcpu *vcpu)
+ kvm_register_write(vcpu, VCPU_REGS_RSI, val);
+ }
+ }
+-
++out:
+ io->count -= io->cur_count;
+ io->cur_count = 0;
+
+@@ -3095,10 +3156,8 @@ int kvm_emulate_pio_string(struct kvm_vc
+ if (!vcpu->arch.pio.in) {
+ /* string PIO write */
+ ret = pio_copy_data(vcpu);
+- if (ret == X86EMUL_PROPAGATE_FAULT) {
+- kvm_inject_gp(vcpu, 0);
++ if (ret == X86EMUL_PROPAGATE_FAULT)
+ return 1;
+- }
+ if (ret == 0 && !pio_string_write(vcpu)) {
+ complete_pio(vcpu);
+ if (vcpu->arch.pio.count == 0)
+@@ -4078,7 +4137,9 @@ static int load_guest_segment_descriptor
+ kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
+ return 1;
+ }
+- return kvm_read_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu);
++ return kvm_read_guest_virt_system(dtable.base + index*8,
++ seg_desc, sizeof(*seg_desc),
++ vcpu, NULL);
+ }
+
+ /* allowed just for 8 bytes segments */
+@@ -4092,15 +4153,23 @@ static int save_guest_segment_descriptor
+
+ if (dtable.limit < index * 8 + 7)
+ return 1;
+- return kvm_write_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu);
++ return kvm_write_guest_virt(dtable.base + index*8, seg_desc, sizeof(*seg_desc), vcpu, NULL);
++}
++
++static gpa_t get_tss_base_addr_write(struct kvm_vcpu *vcpu,
++ struct desc_struct *seg_desc)
++{
++ u32 base_addr = get_desc_base(seg_desc);
++
++ return kvm_mmu_gva_to_gpa_write(vcpu, base_addr, NULL);
+ }
+
+-static gpa_t get_tss_base_addr(struct kvm_vcpu *vcpu,
++static gpa_t get_tss_base_addr_read(struct kvm_vcpu *vcpu,
+ struct desc_struct *seg_desc)
+ {
+ u32 base_addr = get_desc_base(seg_desc);
+
+- return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr);
++ return kvm_mmu_gva_to_gpa_read(vcpu, base_addr, NULL);
+ }
+
+ static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
+@@ -4303,7 +4372,7 @@ static int kvm_task_switch_16(struct kvm
+ sizeof tss_segment_16))
+ goto out;
+
+- if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
++ if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
+ &tss_segment_16, sizeof tss_segment_16))
+ goto out;
+
+@@ -4311,7 +4380,7 @@ static int kvm_task_switch_16(struct kvm
+ tss_segment_16.prev_task_link = old_tss_sel;
+
+ if (kvm_write_guest(vcpu->kvm,
+- get_tss_base_addr(vcpu, nseg_desc),
++ get_tss_base_addr_write(vcpu, nseg_desc),
+ &tss_segment_16.prev_task_link,
+ sizeof tss_segment_16.prev_task_link))
+ goto out;
+@@ -4342,7 +4411,7 @@ static int kvm_task_switch_32(struct kvm
+ sizeof tss_segment_32))
+ goto out;
+
+- if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
++ if (kvm_read_guest(vcpu->kvm, get_tss_base_addr_read(vcpu, nseg_desc),
+ &tss_segment_32, sizeof tss_segment_32))
+ goto out;
+
+@@ -4350,7 +4419,7 @@ static int kvm_task_switch_32(struct kvm
+ tss_segment_32.prev_task_link = old_tss_sel;
+
+ if (kvm_write_guest(vcpu->kvm,
+- get_tss_base_addr(vcpu, nseg_desc),
++ get_tss_base_addr_write(vcpu, nseg_desc),
+ &tss_segment_32.prev_task_link,
+ sizeof tss_segment_32.prev_task_link))
+ goto out;
+@@ -4373,7 +4442,7 @@ int kvm_task_switch(struct kvm_vcpu *vcp
+ u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
+ u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
+
+- old_tss_base = vcpu->arch.mmu.gva_to_gpa(vcpu, old_tss_base);
++ old_tss_base = kvm_mmu_gva_to_gpa_write(vcpu, old_tss_base, NULL);
+
+ /* FIXME: Handle errors. Failure to read either TSS or their
+ * descriptors should generate a pagefault.
+@@ -4582,7 +4651,7 @@ int kvm_arch_vcpu_ioctl_translate(struct
+
+ vcpu_load(vcpu);
+ down_read(&vcpu->kvm->slots_lock);
+- gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, vaddr);
++ gpa = kvm_mmu_gva_to_gpa_system(vcpu, vaddr, NULL);
+ up_read(&vcpu->kvm->slots_lock);
+ tr->physical_address = gpa;
+ tr->valid = gpa != UNMAPPED_GVA;
--- /dev/null
+From stefan.bader@canonical.com Wed Apr 7 14:42:41 2010
+From: Gleb Natapov <gleb@redhat.com>
+Date: Fri, 19 Mar 2010 15:47:33 +0100
+Subject: KVM: x86 emulator: Fix popf emulation
+To: stable@kernel.org
+Cc: Marcelo Tosatti <mtosatti@redhat.com>, Avi Kivity <avi@redhat.com>, Gleb Natapov <gleb@redhat.com>
+Message-ID: <1269010059-25309-6-git-send-email-stefan.bader@canonical.com>
+
+
+From: Gleb Natapov <gleb@redhat.com>
+
+commit d4c6a1549c056f1d817e8f6f2f97d8b44933472f upstream
+
+POPF behaves differently depending on current CPU mode. Emulate correct
+logic to prevent guest from changing flags that it can't change otherwise.
+
+Signed-off-by: Gleb Natapov <gleb@redhat.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/kvm/emulate.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 54 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/kvm/emulate.c
++++ b/arch/x86/kvm/emulate.c
+@@ -339,11 +339,18 @@ static u32 group2_table[] = {
+ };
+
+ /* EFLAGS bit definitions. */
++#define EFLG_ID (1<<21)
++#define EFLG_VIP (1<<20)
++#define EFLG_VIF (1<<19)
++#define EFLG_AC (1<<18)
+ #define EFLG_VM (1<<17)
+ #define EFLG_RF (1<<16)
++#define EFLG_IOPL (3<<12)
++#define EFLG_NT (1<<14)
+ #define EFLG_OF (1<<11)
+ #define EFLG_DF (1<<10)
+ #define EFLG_IF (1<<9)
++#define EFLG_TF (1<<8)
+ #define EFLG_SF (1<<7)
+ #define EFLG_ZF (1<<6)
+ #define EFLG_AF (1<<4)
+@@ -1205,6 +1212,49 @@ static int emulate_pop(struct x86_emulat
+ return rc;
+ }
+
++static int emulate_popf(struct x86_emulate_ctxt *ctxt,
++ struct x86_emulate_ops *ops,
++ void *dest, int len)
++{
++ int rc;
++ unsigned long val, change_mask;
++ int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
++ int cpl = kvm_x86_ops->get_cpl(ctxt->vcpu);
++
++ rc = emulate_pop(ctxt, ops, &val, len);
++ if (rc != X86EMUL_CONTINUE)
++ return rc;
++
++ change_mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_OF
++ | EFLG_TF | EFLG_DF | EFLG_NT | EFLG_RF | EFLG_AC | EFLG_ID;
++
++ switch(ctxt->mode) {
++ case X86EMUL_MODE_PROT64:
++ case X86EMUL_MODE_PROT32:
++ case X86EMUL_MODE_PROT16:
++ if (cpl == 0)
++ change_mask |= EFLG_IOPL;
++ if (cpl <= iopl)
++ change_mask |= EFLG_IF;
++ break;
++ case X86EMUL_MODE_VM86:
++ if (iopl < 3) {
++ kvm_inject_gp(ctxt->vcpu, 0);
++ return X86EMUL_PROPAGATE_FAULT;
++ }
++ change_mask |= EFLG_IF;
++ break;
++ default: /* real mode */
++ change_mask |= (EFLG_IOPL | EFLG_IF);
++ break;
++ }
++
++ *(unsigned long *)dest =
++ (ctxt->eflags & ~change_mask) | (val & change_mask);
++
++ return rc;
++}
++
+ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+ {
+@@ -1995,7 +2045,10 @@ special_insn:
+ c->dst.type = OP_REG;
+ c->dst.ptr = (unsigned long *) &ctxt->eflags;
+ c->dst.bytes = c->op_bytes;
+- goto pop_instruction;
++ rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
++ if (rc != X86EMUL_CONTINUE)
++ goto done;
++ break;
+ case 0xa0 ... 0xa1: /* mov */
+ c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
+ c->dst.val = c->src.val;
--- /dev/null
+From 68b0ddb289220b6d4d865be128939663be34959d Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Mon, 5 Apr 2010 10:51:26 +0900
+Subject: libata: disable NCQ on Crucial C300 SSD
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 68b0ddb289220b6d4d865be128939663be34959d upstream.
+
+Crucial said,
+
+ Thank you for contacting us. We know that with our M225 line of SSDs
+ you sometimes need to disable NCQ (native command queuing) to avoid
+ just the type of errors you're seeing. Our recommendation for the
+ M225 is to add libata.force=noncq to your Linux kernel boot options,
+ under the kernel ATA library option.
+
+ I have sent your feedback to the engineers working on the C300, and
+ asked them to please pass it on to the firmware team. I have been
+ notified that they are in the process of testing and finalizing a
+ new firmware version, that you can expect to see released around the
+ end of April. We’ll keep you posted as to when it will be available
+ for download.
+
+So, turn off NCQ on the drive w/ the current firmware revision.
+
+Reported in the following bug.
+
+ https://bugzilla.kernel.org/show_bug.cgi?id=15573
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: lethalwp@scarlet.be
+Reported-by: Luke Macken <lmacken@redhat.com>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/libata-core.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -4348,6 +4348,9 @@ static const struct ata_blacklist_entry
+ { "HTS541080G9SA00", "MB4OC60D", ATA_HORKAGE_NONCQ, },
+ { "HTS541010G9SA00", "MBZOC60D", ATA_HORKAGE_NONCQ, },
+
++ /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */
++ { "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, },
++
+ /* devices which puke on READ_NATIVE_MAX */
+ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, },
+ { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA },
--- /dev/null
+From 445d211b0da4e9a6e6d576edff85085c2aaf53df Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Mon, 5 Apr 2010 10:33:13 +0900
+Subject: libata: unlock HPA if device shrunk
+
+From: Tejun Heo <tj@kernel.org>
+
+commit 445d211b0da4e9a6e6d576edff85085c2aaf53df upstream.
+
+Some BIOSes don't configure HPA during boot but do so while resuming.
+This causes harddrives to shrink during resume making libata detach
+and reattach them. This can be worked around by unlocking HPA if old
+size equals native size.
+
+Add ATA_DFLAG_UNLOCK_HPA so that HPA unlocking can be controlled
+per-device and update ata_dev_revalidate() such that it sets
+ATA_DFLAG_UNLOCK_HPA and fails with -EIO when the above condition is
+detected.
+
+This patch fixes the following bug.
+
+ https://bugzilla.kernel.org/show_bug.cgi?id=15396
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reported-by: Oleksandr Yermolenko <yaa.bta@gmail.com>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+
+---
+ drivers/ata/libata-core.c | 74 +++++++++++++++++++++++++++-------------------
+ include/linux/libata.h | 1
+ 2 files changed, 46 insertions(+), 29 deletions(-)
+
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -1493,6 +1493,7 @@ static int ata_hpa_resize(struct ata_dev
+ {
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
++ bool unlock_hpa = ata_ignore_hpa || dev->flags & ATA_DFLAG_UNLOCK_HPA;
+ u64 sectors = ata_id_n_sectors(dev->id);
+ u64 native_sectors;
+ int rc;
+@@ -1509,7 +1510,7 @@ static int ata_hpa_resize(struct ata_dev
+ /* If device aborted the command or HPA isn't going to
+ * be unlocked, skip HPA resizing.
+ */
+- if (rc == -EACCES || !ata_ignore_hpa) {
++ if (rc == -EACCES || !unlock_hpa) {
+ ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+ "broken, skipping HPA handling\n");
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+@@ -1524,7 +1525,7 @@ static int ata_hpa_resize(struct ata_dev
+ dev->n_native_sectors = native_sectors;
+
+ /* nothing to do? */
+- if (native_sectors <= sectors || !ata_ignore_hpa) {
++ if (native_sectors <= sectors || !unlock_hpa) {
+ if (!print_info || native_sectors == sectors)
+ return 0;
+
+@@ -4180,36 +4181,51 @@ int ata_dev_revalidate(struct ata_device
+ goto fail;
+
+ /* verify n_sectors hasn't changed */
+- if (dev->class == ATA_DEV_ATA && n_sectors &&
+- dev->n_sectors != n_sectors) {
+- ata_dev_printk(dev, KERN_WARNING, "n_sectors mismatch "
+- "%llu != %llu\n",
+- (unsigned long long)n_sectors,
+- (unsigned long long)dev->n_sectors);
+- /*
+- * Something could have caused HPA to be unlocked
+- * involuntarily. If n_native_sectors hasn't changed
+- * and the new size matches it, keep the device.
+- */
+- if (dev->n_native_sectors == n_native_sectors &&
+- dev->n_sectors > n_sectors &&
+- dev->n_sectors == n_native_sectors) {
+- ata_dev_printk(dev, KERN_WARNING,
+- "new n_sectors matches native, probably "
+- "late HPA unlock, continuing\n");
+- /* keep using the old n_sectors */
+- dev->n_sectors = n_sectors;
+- } else {
+- /* restore original n_[native]_sectors and fail */
+- dev->n_native_sectors = n_native_sectors;
+- dev->n_sectors = n_sectors;
+- rc = -ENODEV;
+- goto fail;
+- }
++ if (dev->class != ATA_DEV_ATA || !n_sectors ||
++ dev->n_sectors == n_sectors)
++ return 0;
++
++ /* n_sectors has changed */
++ ata_dev_printk(dev, KERN_WARNING, "n_sectors mismatch %llu != %llu\n",
++ (unsigned long long)n_sectors,
++ (unsigned long long)dev->n_sectors);
++
++ /*
++ * Something could have caused HPA to be unlocked
++ * involuntarily. If n_native_sectors hasn't changed and the
++ * new size matches it, keep the device.
++ */
++ if (dev->n_native_sectors == n_native_sectors &&
++ dev->n_sectors > n_sectors && dev->n_sectors == n_native_sectors) {
++ ata_dev_printk(dev, KERN_WARNING,
++ "new n_sectors matches native, probably "
++ "late HPA unlock, continuing\n");
++ /* keep using the old n_sectors */
++ dev->n_sectors = n_sectors;
++ return 0;
+ }
+
+- return 0;
++ /*
++ * Some BIOSes boot w/o HPA but resume w/ HPA locked. Try
++ * unlocking HPA in those cases.
++ *
++ * https://bugzilla.kernel.org/show_bug.cgi?id=15396
++ */
++ if (dev->n_native_sectors == n_native_sectors &&
++ dev->n_sectors < n_sectors && n_sectors == n_native_sectors &&
++ !(dev->horkage & ATA_HORKAGE_BROKEN_HPA)) {
++ ata_dev_printk(dev, KERN_WARNING,
++ "old n_sectors matches native, probably "
++ "late HPA lock, will try to unlock HPA\n");
++ /* try unlocking HPA */
++ dev->flags |= ATA_DFLAG_UNLOCK_HPA;
++ rc = -EIO;
++ } else
++ rc = -ENODEV;
+
++ /* restore original n_[native_]sectors and fail */
++ dev->n_native_sectors = n_native_sectors;
++ dev->n_sectors = n_sectors;
+ fail:
+ ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
+ return rc;
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -146,6 +146,7 @@ enum {
+ ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */
+ ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */
+ ATA_DFLAG_NO_UNLOAD = (1 << 17), /* device doesn't support unload */
++ ATA_DFLAG_UNLOCK_HPA = (1 << 18), /* unlock HPA */
+ ATA_DFLAG_INIT_MASK = (1 << 24) - 1,
+
+ ATA_DFLAG_DETACH = (1 << 24),
--- /dev/null
+From 4f1deba435ef75380c1d06fda860c7a15ea16fdf Mon Sep 17 00:00:00 2001
+From: JosephChan@via.com.tw <JosephChan@via.com.tw>
+Date: Fri, 19 Mar 2010 14:08:11 +0800
+Subject: pata_via: Add VIA VX900 support
+
+From: JosephChan@via.com.tw <JosephChan@via.com.tw>
+
+commit 4f1deba435ef75380c1d06fda860c7a15ea16fdf upstream.
+
+Signed-off-by: Joseph Chan <josephchan@via.com.tw>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/pata_via.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/ata/pata_via.c
++++ b/drivers/ata/pata_via.c
+@@ -661,6 +661,7 @@ static const struct pci_device_id via[]
+ { PCI_VDEVICE(VIA, 0x3164), },
+ { PCI_VDEVICE(VIA, 0x5324), },
+ { PCI_VDEVICE(VIA, 0xC409), VIA_IDFLAG_SINGLE },
++ { PCI_VDEVICE(VIA, 0x9001), VIA_IDFLAG_SINGLE },
+
+ { },
+ };
--- /dev/null
+From 55ab3a1ff843e3f0e24d2da44e71bffa5d853010 Mon Sep 17 00:00:00 2001
+From: Anton Blanchard <anton@samba.org>
+Date: Tue, 6 Apr 2010 14:34:58 -0700
+Subject: raw: fsync method is now required
+
+From: Anton Blanchard <anton@samba.org>
+
+commit 55ab3a1ff843e3f0e24d2da44e71bffa5d853010 upstream.
+
+Commit 148f948ba877f4d3cdef036b1ff6d9f68986706a (vfs: Introduce new
+helpers for syncing after writing to O_SYNC file or IS_SYNC inode) broke
+the raw driver.
+
+We now call through generic_file_aio_write -> generic_write_sync ->
+vfs_fsync_range. vfs_fsync_range has:
+
+ if (!fop || !fop->fsync) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+But drivers/char/raw.c doesn't set an fsync method.
+
+We have two options: fix it or remove the raw driver completely. I'm
+happy to do either, the fact this has been broken for so long suggests it
+is rarely used.
+
+The patch below adds an fsync method to the raw driver. My knowledge of
+the block layer is pretty sketchy so this could do with a once over.
+
+If we instead decide to remove the raw driver, this patch might still be
+useful as a backport to 2.6.33 and 2.6.32.
+
+Signed-off-by: Anton Blanchard <anton@samba.org>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Alexander Viro <viro@zeniv.linux.org.uk>
+Cc: Jens Axboe <jens.axboe@oracle.com>
+Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
+Tested-by: Jeff Moyer <jmoyer@redhat.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/raw.c | 1 +
+ fs/block_dev.c | 3 ++-
+ include/linux/fs.h | 1 +
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/char/raw.c
++++ b/drivers/char/raw.c
+@@ -247,6 +247,7 @@ static const struct file_operations raw_
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = blkdev_aio_write,
++ .fsync = block_fsync,
+ .open = raw_open,
+ .release= raw_release,
+ .ioctl = raw_ioctl,
+--- a/fs/block_dev.c
++++ b/fs/block_dev.c
+@@ -404,7 +404,7 @@ static loff_t block_llseek(struct file *
+ * NULL first argument is nfsd_sync_dir() and that's not a directory.
+ */
+
+-static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
++int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
+ {
+ return sync_blockdev(I_BDEV(filp->f_mapping->host));
+ }
+@@ -423,6 +423,7 @@ static struct inode *bdev_alloc_inode(st
+ return NULL;
+ return &ei->vfs_inode;
+ }
++EXPORT_SYMBOL(block_fsync);
+
+ static void bdev_destroy_inode(struct inode *inode)
+ {
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2225,6 +2225,7 @@ extern int generic_segment_checks(const
+ /* fs/block_dev.c */
+ extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
++extern int block_fsync(struct file *filp, struct dentry *dentry, int datasync);
+
+ /* fs/splice.c */
+ extern ssize_t generic_file_splice_read(struct file *, loff_t *,
--- /dev/null
+From 70655c06bd3f25111312d63985888112aed15ac5 Mon Sep 17 00:00:00 2001
+From: Wu Fengguang <fengguang.wu@intel.com>
+Date: Tue, 6 Apr 2010 14:34:53 -0700
+Subject: readahead: fix NULL filp dereference
+
+From: Wu Fengguang <fengguang.wu@intel.com>
+
+commit 70655c06bd3f25111312d63985888112aed15ac5 upstream.
+
+btrfs relocate_file_extent_cluster() calls us with NULL filp:
+
+ [ 4005.426805] BUG: unable to handle kernel NULL pointer dereference at 00000021
+ [ 4005.426818] IP: [<c109a130>] page_cache_sync_readahead+0x18/0x3e
+
+Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
+Cc: Yan Zheng <yanzheng@21cn.com>
+Reported-by: Kirill A. Shutemov <kirill@shutemov.name>
+Tested-by: Kirill A. Shutemov <kirill@shutemov.name>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/readahead.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/readahead.c
++++ b/mm/readahead.c
+@@ -502,7 +502,7 @@ void page_cache_sync_readahead(struct ad
+ return;
+
+ /* be dumb */
+- if (filp->f_mode & FMODE_RANDOM) {
++ if (filp && (filp->f_mode & FMODE_RANDOM)) {
+ force_page_cache_readahead(mapping, filp, offset, req_size);
+ return;
+ }
--- /dev/null
+From max@stro.at Wed Apr 7 14:36:07 2010
+From: Jiri Slaby <jslaby@suse.cz>
+Date: Fri, 19 Mar 2010 02:51:56 +0100
+Subject: resource: move kernel function inside __KERNEL__
+To: Greg KH <greg@kroah.com>
+Cc: stable@kernel.org, Jiri Slaby <jslaby@suse.cz>
+Message-ID: <20100319015156.GC4424@stro.at>
+
+commit 96d07d211739fd2450ac54e81d00fa40fcd4b1bd upstream
+From: Jiri Slaby <jslaby@suse.cz>
+
+resource: move kernel function inside __KERNEL__
+
+It is an internal function. Move it inside __KERNEL__ ifdef, along
+with task_struct declaration.
+
+Then we get:
+#--- /usr/include/linux/resource.h 2009-09-14 15:09:29.000000000 +0200
+#+++ usr/include/linux/resource.h 2010-01-04 11:30:54.000000000 +0100
+#@@ -3,8 +3,6 @@
+#
+##include <linux/time.h>
+#
+#-struct task_struct;
+#-
+#/*
+#* Resource control/accounting header file for linux
+#*/
+#@@ -70,6 +68,5 @@
+#*/
+##include <asm/resource.h>
+#
+#-int getrusage(struct task_struct *p, int who, struct rusage *ru);
+#
+##endif
+#
+#***********
+
+include/linux/Kbuild is untouched, since unifdef is run even on
+headers-y nowadays.
+
+backport to 2.6.32 by maximilian attems <max@stro.at>
+Patch commented out by gregkh due to quilt complaining.
+
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Cc: maximilian attems <max@stro.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/resource.h | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/include/linux/resource.h
++++ b/include/linux/resource.h
+@@ -3,8 +3,6 @@
+
+ #include <linux/time.h>
+
+-struct task_struct;
+-
+ /*
+ * Resource control/accounting header file for linux
+ */
+@@ -70,6 +68,12 @@ struct rlimit {
+ */
+ #include <asm/resource.h>
+
++#ifdef __KERNEL__
++
++struct task_struct;
++
+ int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
+
++#endif /* __KERNEL__ */
++
+ #endif
tty-release_one_tty-forgets-to-put-pids.patch
lis3-fix-show-rate-for-8-bits-chips.patch
pata_ali-fix-regression-with-old-devices.patch
+hid-fix-oops-in-gyration_event.patch
+raw-fsync-method-is-now-required.patch
+readahead-fix-null-filp-dereference.patch
+alsa-mixart-range-checking-proc-file.patch
+alsa-hda-fix-0-db-offset-for-lenovo-thinkpad-models-using-ad1981.patch
+x86-amd-get-multi-node-cpu-info-from-nodeid-msr-instead-of-pci-config-space.patch
+resource-move-kernel-function-inside-__kernel__.patch
+backlight-mbp_nvidia_bl-add-five-more-macbook-variants.patch
+kvm-x86-emulator-add-virtual-8086-mode-of-emulation.patch
+kvm-x86-emulator-fix-memory-access-during-x86-emulation.patch
+kvm-x86-emulator-check-iopl-level-during-io-instruction-emulation.patch
+kvm-x86-emulator-fix-popf-emulation.patch
+kvm-fix-segment-descriptor-loading.patch
+kvm-vmx-update-instruction-length-on-intercepted-bp.patch
+kvm-vmx-use-macros-instead-of-hex-value-on-cr0-initialization.patch
+kvm-svm-reset-cr0-properly-on-vcpu-reset.patch
+kvm-vmx-disable-unrestricted-guest-when-ept-disabled.patch
+kvm-x86-disable-paravirt-mmu-reporting.patch
+pata_via-add-via-vx900-support.patch
+ext3-don-t-update-the-superblock-in-ext3_statfs.patch
+ext3-journal-all-modifications-in-ext3_xattr_set_handle.patch
+thinkpad-acpi-fix-some-version-quirks.patch
+thinkpad-acpi-issue-backlight-class-events.patch
+thinkpad-acpi-silence-bogus-complain-during-rmmod.patch
+thinkpad-acpi-adopt-input-device.patch
+thinkpad-acpi-expose-module-parameters.patch
+thinkpad-acpi-log-temperatures-on-termal-alarm-v2.patch
+thinkpad-acpi-use-input_set_capability.patch
+thinkpad-acpi-sync-input-device-ev_sw-initial-state.patch
+thinkpad-acpi-log-initial-state-of-rfkill-switches.patch
+thinkpad-acpi-convert-to-seq_file.patch
+thinkpad-acpi-lock-down-video-output-state-access.patch
+eeepc-laptop-disable-cpu-speed-control-on-eeepc-701.patch
+eeepc-laptop-dmi-blacklist-to-disable-pci-hotplug-code.patch
+eeepc-laptop-add-hotplug_disable-parameter.patch
+eeepc-laptop-disable-wireless-hotplug-for-1201n.patch
+eeepc-laptop-disable-wireless-hotplug-for-1005pe.patch
+libata-disable-ncq-on-crucial-c300-ssd.patch
+libata-unlock-hpa-if-device-shrunk.patch
--- /dev/null
+From d112ef95d4ec1ee7fe7123e3f21e4aac0d57570c Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:26 +0000
+Subject: thinkpad-acpi: adopt input device
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit d112ef95d4ec1ee7fe7123e3f21e4aac0d57570c upstream.
+
+Properly init the parent field of the input device. Thanks to Alan
+Jenkins, who noted this problem in a different driver.
+
+Reported-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -8385,6 +8385,7 @@ static int __init thinkpad_acpi_module_i
+ PCI_VENDOR_ID_IBM;
+ tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+ tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
++ tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev;
+ }
+ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+ ret = ibm_init(&ibms_init[i]);
--- /dev/null
+From 887965e6576a78f71b9b98dec43fd1c73becd2e8 Mon Sep 17 00:00:00 2001
+From: Alexey Dobriyan <adobriyan@gmail.com>
+Date: Tue, 15 Dec 2009 21:51:12 -0200
+Subject: thinkpad-acpi: convert to seq_file
+
+From: Alexey Dobriyan <adobriyan@gmail.com>
+
+commit 887965e6576a78f71b9b98dec43fd1c73becd2e8 upstream.
+
+(hmh@hmh.eng.br: Updated to apply to 2.6.32.y)
+
+Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 282 ++++++++++++++++-------------------
+ 1 file changed, 131 insertions(+), 151 deletions(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -61,6 +61,7 @@
+
+ #include <linux/nvram.h>
+ #include <linux/proc_fs.h>
++#include <linux/seq_file.h>
+ #include <linux/sysfs.h>
+ #include <linux/backlight.h>
+ #include <linux/fb.h>
+@@ -256,7 +257,7 @@ struct tp_acpi_drv_struct {
+ struct ibm_struct {
+ char *name;
+
+- int (*read) (char *);
++ int (*read) (struct seq_file *);
+ int (*write) (char *);
+ void (*exit) (void);
+ void (*resume) (void);
+@@ -776,36 +777,25 @@ static int __init register_tpacpi_subdri
+ ****************************************************************************
+ ****************************************************************************/
+
+-static int dispatch_procfs_read(char *page, char **start, off_t off,
+- int count, int *eof, void *data)
++static int dispatch_proc_show(struct seq_file *m, void *v)
+ {
+- struct ibm_struct *ibm = data;
+- int len;
++ struct ibm_struct *ibm = m->private;
+
+ if (!ibm || !ibm->read)
+ return -EINVAL;
++ return ibm->read(m);
++}
+
+- len = ibm->read(page);
+- if (len < 0)
+- return len;
+-
+- if (len <= off + count)
+- *eof = 1;
+- *start = page + off;
+- len -= off;
+- if (len > count)
+- len = count;
+- if (len < 0)
+- len = 0;
+-
+- return len;
++static int dispatch_proc_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, dispatch_proc_show, PDE(inode)->data);
+ }
+
+-static int dispatch_procfs_write(struct file *file,
++static ssize_t dispatch_proc_write(struct file *file,
+ const char __user *userbuf,
+- unsigned long count, void *data)
++ size_t count, loff_t *pos)
+ {
+- struct ibm_struct *ibm = data;
++ struct ibm_struct *ibm = PDE(file->f_path.dentry->d_inode)->data;
+ char *kernbuf;
+ int ret;
+
+@@ -834,6 +824,15 @@ static int dispatch_procfs_write(struct
+ return ret;
+ }
+
++static const struct file_operations dispatch_proc_fops = {
++ .owner = THIS_MODULE,
++ .open = dispatch_proc_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++ .write = dispatch_proc_write,
++};
++
+ static char *next_cmd(char **cmds)
+ {
+ char *start = *cmds;
+@@ -1388,12 +1387,11 @@ static ssize_t tpacpi_rfk_sysfs_enable_s
+ }
+
+ /* procfs -------------------------------------------------------------- */
+-static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p)
++static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id,
++ struct seq_file *m)
+ {
+- int len = 0;
+-
+ if (id >= TPACPI_RFK_SW_MAX)
+- len += sprintf(p + len, "status:\t\tnot supported\n");
++ seq_printf(m, "status:\t\tnot supported\n");
+ else {
+ int status;
+
+@@ -1407,13 +1405,13 @@ static int tpacpi_rfk_procfs_read(const
+ return status;
+ }
+
+- len += sprintf(p + len, "status:\t\t%s\n",
++ seq_printf(m, "status:\t\t%s\n",
+ (status == TPACPI_RFK_RADIO_ON) ?
+ "enabled" : "disabled");
+- len += sprintf(p + len, "commands:\tenable, disable\n");
++ seq_printf(m, "commands:\tenable, disable\n");
+ }
+
+- return len;
++ return 0;
+ }
+
+ static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
+@@ -1891,14 +1889,11 @@ static int __init thinkpad_acpi_driver_i
+ return 0;
+ }
+
+-static int thinkpad_acpi_driver_read(char *p)
++static int thinkpad_acpi_driver_read(struct seq_file *m)
+ {
+- int len = 0;
+-
+- len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC);
+- len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
+-
+- return len;
++ seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC);
++ seq_printf(m, "version:\t%s\n", TPACPI_VERSION);
++ return 0;
+ }
+
+ static struct ibm_struct thinkpad_acpi_driver_data = {
+@@ -3754,14 +3749,13 @@ static void hotkey_resume(void)
+ }
+
+ /* procfs -------------------------------------------------------------- */
+-static int hotkey_read(char *p)
++static int hotkey_read(struct seq_file *m)
+ {
+ int res, status;
+- int len = 0;
+
+ if (!tp_features.hotkey) {
+- len += sprintf(p + len, "status:\t\tnot supported\n");
+- return len;
++ seq_printf(m, "status:\t\tnot supported\n");
++ return 0;
+ }
+
+ if (mutex_lock_killable(&hotkey_mutex))
+@@ -3773,17 +3767,16 @@ static int hotkey_read(char *p)
+ if (res)
+ return res;
+
+- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
++ seq_printf(m, "status:\t\t%s\n", enabled(status, 0));
+ if (hotkey_all_mask) {
+- len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask);
+- len += sprintf(p + len,
+- "commands:\tenable, disable, reset, <mask>\n");
++ seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask);
++ seq_printf(m, "commands:\tenable, disable, reset, <mask>\n");
+ } else {
+- len += sprintf(p + len, "mask:\t\tnot supported\n");
+- len += sprintf(p + len, "commands:\tenable, disable, reset\n");
++ seq_printf(m, "mask:\t\tnot supported\n");
++ seq_printf(m, "commands:\tenable, disable, reset\n");
+ }
+
+- return len;
++ return 0;
+ }
+
+ static void hotkey_enabledisable_warn(bool enable)
+@@ -4050,9 +4043,9 @@ static int __init bluetooth_init(struct
+ }
+
+ /* procfs -------------------------------------------------------------- */
+-static int bluetooth_read(char *p)
++static int bluetooth_read(struct seq_file *m)
+ {
+- return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p);
++ return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, m);
+ }
+
+ static int bluetooth_write(char *buf)
+@@ -4241,9 +4234,9 @@ static int __init wan_init(struct ibm_in
+ }
+
+ /* procfs -------------------------------------------------------------- */
+-static int wan_read(char *p)
++static int wan_read(struct seq_file *m)
+ {
+- return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p);
++ return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, m);
+ }
+
+ static int wan_write(char *buf)
+@@ -4618,14 +4611,13 @@ static int video_expand_toggle(void)
+ /* not reached */
+ }
+
+-static int video_read(char *p)
++static int video_read(struct seq_file *m)
+ {
+ int status, autosw;
+- int len = 0;
+
+ if (video_supported == TPACPI_VIDEO_NONE) {
+- len += sprintf(p + len, "status:\t\tnot supported\n");
+- return len;
++ seq_printf(m, "status:\t\tnot supported\n");
++ return 0;
+ }
+
+ status = video_outputsw_get();
+@@ -4636,20 +4628,20 @@ static int video_read(char *p)
+ if (autosw < 0)
+ return autosw;
+
+- len += sprintf(p + len, "status:\t\tsupported\n");
+- len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+- len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
++ seq_printf(m, "status:\t\tsupported\n");
++ seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0));
++ seq_printf(m, "crt:\t\t%s\n", enabled(status, 1));
+ if (video_supported == TPACPI_VIDEO_NEW)
+- len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+- len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
+- len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
+- len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
++ seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3));
++ seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0));
++ seq_printf(m, "commands:\tlcd_enable, lcd_disable\n");
++ seq_printf(m, "commands:\tcrt_enable, crt_disable\n");
+ if (video_supported == TPACPI_VIDEO_NEW)
+- len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
+- len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
+- len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
++ seq_printf(m, "commands:\tdvi_enable, dvi_disable\n");
++ seq_printf(m, "commands:\tauto_enable, auto_disable\n");
++ seq_printf(m, "commands:\tvideo_switch, expand_toggle\n");
+
+- return len;
++ return 0;
+ }
+
+ static int video_write(char *buf)
+@@ -4841,25 +4833,24 @@ static void light_exit(void)
+ flush_workqueue(tpacpi_wq);
+ }
+
+-static int light_read(char *p)
++static int light_read(struct seq_file *m)
+ {
+- int len = 0;
+ int status;
+
+ if (!tp_features.light) {
+- len += sprintf(p + len, "status:\t\tnot supported\n");
++ seq_printf(m, "status:\t\tnot supported\n");
+ } else if (!tp_features.light_status) {
+- len += sprintf(p + len, "status:\t\tunknown\n");
+- len += sprintf(p + len, "commands:\ton, off\n");
++ seq_printf(m, "status:\t\tunknown\n");
++ seq_printf(m, "commands:\ton, off\n");
+ } else {
+ status = light_get_status();
+ if (status < 0)
+ return status;
+- len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+- len += sprintf(p + len, "commands:\ton, off\n");
++ seq_printf(m, "status:\t\t%s\n", onoff(status, 0));
++ seq_printf(m, "commands:\ton, off\n");
+ }
+
+- return len;
++ return 0;
+ }
+
+ static int light_write(char *buf)
+@@ -4937,20 +4928,18 @@ static void cmos_exit(void)
+ device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+ }
+
+-static int cmos_read(char *p)
++static int cmos_read(struct seq_file *m)
+ {
+- int len = 0;
+-
+ /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ R30, R31, T20-22, X20-21 */
+ if (!cmos_handle)
+- len += sprintf(p + len, "status:\t\tnot supported\n");
++ seq_printf(m, "status:\t\tnot supported\n");
+ else {
+- len += sprintf(p + len, "status:\t\tsupported\n");
+- len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
++ seq_printf(m, "status:\t\tsupported\n");
++ seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n");
+ }
+
+- return len;
++ return 0;
+ }
+
+ static int cmos_write(char *buf)
+@@ -5325,15 +5314,13 @@ static int __init led_init(struct ibm_in
+ ((s) == TPACPI_LED_OFF ? "off" : \
+ ((s) == TPACPI_LED_ON ? "on" : "blinking"))
+
+-static int led_read(char *p)
++static int led_read(struct seq_file *m)
+ {
+- int len = 0;
+-
+ if (!led_supported) {
+- len += sprintf(p + len, "status:\t\tnot supported\n");
+- return len;
++ seq_printf(m, "status:\t\tnot supported\n");
++ return 0;
+ }
+- len += sprintf(p + len, "status:\t\tsupported\n");
++ seq_printf(m, "status:\t\tsupported\n");
+
+ if (led_supported == TPACPI_LED_570) {
+ /* 570 */
+@@ -5342,15 +5329,15 @@ static int led_read(char *p)
+ status = led_get_status(i);
+ if (status < 0)
+ return -EIO;
+- len += sprintf(p + len, "%d:\t\t%s\n",
++ seq_printf(m, "%d:\t\t%s\n",
+ i, str_led_status(status));
+ }
+ }
+
+- len += sprintf(p + len, "commands:\t"
++ seq_printf(m, "commands:\t"
+ "<led> on, <led> off, <led> blink (<led> is 0-15)\n");
+
+- return len;
++ return 0;
+ }
+
+ static int led_write(char *buf)
+@@ -5423,18 +5410,16 @@ static int __init beep_init(struct ibm_i
+ return (beep_handle)? 0 : 1;
+ }
+
+-static int beep_read(char *p)
++static int beep_read(struct seq_file *m)
+ {
+- int len = 0;
+-
+ if (!beep_handle)
+- len += sprintf(p + len, "status:\t\tnot supported\n");
++ seq_printf(m, "status:\t\tnot supported\n");
+ else {
+- len += sprintf(p + len, "status:\t\tsupported\n");
+- len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
++ seq_printf(m, "status:\t\tsupported\n");
++ seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n");
+ }
+
+- return len;
++ return 0;
+ }
+
+ static int beep_write(char *buf)
+@@ -5795,9 +5780,8 @@ static void thermal_exit(void)
+ }
+ }
+
+-static int thermal_read(char *p)
++static int thermal_read(struct seq_file *m)
+ {
+- int len = 0;
+ int n, i;
+ struct ibm_thermal_sensors_struct t;
+
+@@ -5805,16 +5789,16 @@ static int thermal_read(char *p)
+ if (unlikely(n < 0))
+ return n;
+
+- len += sprintf(p + len, "temperatures:\t");
++ seq_printf(m, "temperatures:\t");
+
+ if (n > 0) {
+ for (i = 0; i < (n - 1); i++)
+- len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+- len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
++ seq_printf(m, "%d ", t.temp[i] / 1000);
++ seq_printf(m, "%d\n", t.temp[i] / 1000);
+ } else
+- len += sprintf(p + len, "not supported\n");
++ seq_printf(m, "not supported\n");
+
+- return len;
++ return 0;
+ }
+
+ static struct ibm_struct thermal_driver_data = {
+@@ -5829,39 +5813,38 @@ static struct ibm_struct thermal_driver_
+
+ static u8 ecdump_regs[256];
+
+-static int ecdump_read(char *p)
++static int ecdump_read(struct seq_file *m)
+ {
+- int len = 0;
+ int i, j;
+ u8 v;
+
+- len += sprintf(p + len, "EC "
++ seq_printf(m, "EC "
+ " +00 +01 +02 +03 +04 +05 +06 +07"
+ " +08 +09 +0a +0b +0c +0d +0e +0f\n");
+ for (i = 0; i < 256; i += 16) {
+- len += sprintf(p + len, "EC 0x%02x:", i);
++ seq_printf(m, "EC 0x%02x:", i);
+ for (j = 0; j < 16; j++) {
+ if (!acpi_ec_read(i + j, &v))
+ break;
+ if (v != ecdump_regs[i + j])
+- len += sprintf(p + len, " *%02x", v);
++ seq_printf(m, " *%02x", v);
+ else
+- len += sprintf(p + len, " %02x", v);
++ seq_printf(m, " %02x", v);
+ ecdump_regs[i + j] = v;
+ }
+- len += sprintf(p + len, "\n");
++ seq_putc(m, '\n');
+ if (j != 16)
+ break;
+ }
+
+ /* These are way too dangerous to advertise openly... */
+ #if 0
+- len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
++ seq_printf(m, "commands:\t0x<offset> 0x<value>"
+ " (<offset> is 00-ff, <value> is 00-ff)\n");
+- len += sprintf(p + len, "commands:\t0x<offset> <value> "
++ seq_printf(m, "commands:\t0x<offset> <value> "
+ " (<offset> is 00-ff, <value> is 0-255)\n");
+ #endif
+- return len;
++ return 0;
+ }
+
+ static int ecdump_write(char *buf)
+@@ -6314,23 +6297,22 @@ static void brightness_exit(void)
+ tpacpi_brightness_checkpoint_nvram();
+ }
+
+-static int brightness_read(char *p)
++static int brightness_read(struct seq_file *m)
+ {
+- int len = 0;
+ int level;
+
+ level = brightness_get(NULL);
+ if (level < 0) {
+- len += sprintf(p + len, "level:\t\tunreadable\n");
++ seq_printf(m, "level:\t\tunreadable\n");
+ } else {
+- 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>"
++ seq_printf(m, "level:\t\t%d\n", level);
++ seq_printf(m, "commands:\tup, down\n");
++ seq_printf(m, "commands:\tlevel <level>"
+ " (<level> is 0-%d)\n",
+ (tp_features.bright_16levels) ? 15 : 7);
+ }
+
+- return len;
++ return 0;
+ }
+
+ static int brightness_write(char *buf)
+@@ -6387,22 +6369,21 @@ static struct ibm_struct brightness_driv
+
+ static int volume_offset = 0x30;
+
+-static int volume_read(char *p)
++static int volume_read(struct seq_file *m)
+ {
+- int len = 0;
+ u8 level;
+
+ if (!acpi_ec_read(volume_offset, &level)) {
+- len += sprintf(p + len, "level:\t\tunreadable\n");
++ seq_printf(m, "level:\t\tunreadable\n");
+ } else {
+- len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
+- len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
+- len += sprintf(p + len, "commands:\tup, down, mute\n");
+- len += sprintf(p + len, "commands:\tlevel <level>"
++ seq_printf(m, "level:\t\t%d\n", level & 0xf);
++ seq_printf(m, "mute:\t\t%s\n", onoff(level, 6));
++ seq_printf(m, "commands:\tup, down, mute\n");
++ seq_printf(m, "commands:\tlevel <level>"
+ " (<level> is 0-15)\n");
+ }
+
+- return len;
++ return 0;
+ }
+
+ static int volume_write(char *buf)
+@@ -7554,9 +7535,8 @@ static void fan_resume(void)
+ }
+ }
+
+-static int fan_read(char *p)
++static int fan_read(struct seq_file *m)
+ {
+- int len = 0;
+ int rc;
+ u8 status;
+ unsigned int speed = 0;
+@@ -7568,7 +7548,7 @@ static int fan_read(char *p)
+ if (rc < 0)
+ return rc;
+
+- len += sprintf(p + len, "status:\t\t%s\n"
++ seq_printf(m, "status:\t\t%s\n"
+ "level:\t\t%d\n",
+ (status != 0) ? "enabled" : "disabled", status);
+ break;
+@@ -7579,54 +7559,54 @@ static int fan_read(char *p)
+ if (rc < 0)
+ return rc;
+
+- len += sprintf(p + len, "status:\t\t%s\n",
++ seq_printf(m, "status:\t\t%s\n",
+ (status != 0) ? "enabled" : "disabled");
+
+ rc = fan_get_speed(&speed);
+ if (rc < 0)
+ return rc;
+
+- len += sprintf(p + len, "speed:\t\t%d\n", speed);
++ seq_printf(m, "speed:\t\t%d\n", speed);
+
+ if (status & TP_EC_FAN_FULLSPEED)
+ /* Disengaged mode takes precedence */
+- len += sprintf(p + len, "level:\t\tdisengaged\n");
++ seq_printf(m, "level:\t\tdisengaged\n");
+ else if (status & TP_EC_FAN_AUTO)
+- len += sprintf(p + len, "level:\t\tauto\n");
++ seq_printf(m, "level:\t\tauto\n");
+ else
+- len += sprintf(p + len, "level:\t\t%d\n", status);
++ seq_printf(m, "level:\t\t%d\n", status);
+ break;
+
+ case TPACPI_FAN_NONE:
+ default:
+- len += sprintf(p + len, "status:\t\tnot supported\n");
++ seq_printf(m, "status:\t\tnot supported\n");
+ }
+
+ if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
+- len += sprintf(p + len, "commands:\tlevel <level>");
++ seq_printf(m, "commands:\tlevel <level>");
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+- len += sprintf(p + len, " (<level> is 0-7)\n");
++ seq_printf(m, " (<level> is 0-7)\n");
+ break;
+
+ default:
+- len += sprintf(p + len, " (<level> is 0-7, "
++ seq_printf(m, " (<level> is 0-7, "
+ "auto, disengaged, full-speed)\n");
+ break;
+ }
+ }
+
+ if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
+- len += sprintf(p + len, "commands:\tenable, disable\n"
++ seq_printf(m, "commands:\tenable, disable\n"
+ "commands:\twatchdog <timeout> (<timeout> "
+ "is 0 (off), 1-120 (seconds))\n");
+
+ if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
+- len += sprintf(p + len, "commands:\tspeed <speed>"
++ seq_printf(m, "commands:\tspeed <speed>"
+ " (<speed> is 0-65535)\n");
+
+- return len;
++ return 0;
+ }
+
+ static int fan_write_cmd_level(const char *cmd, int *rc)
+@@ -7907,19 +7887,19 @@ static int __init ibm_init(struct ibm_in
+ "%s installed\n", ibm->name);
+
+ if (ibm->read) {
+- entry = create_proc_entry(ibm->name,
+- S_IFREG | S_IRUGO | S_IWUSR,
+- proc_dir);
++ mode_t mode;
++
++ mode = S_IRUGO;
++ if (ibm->write)
++ mode |= S_IWUSR;
++ entry = proc_create_data(ibm->name, mode, proc_dir,
++ &dispatch_proc_fops, ibm);
+ if (!entry) {
+ printk(TPACPI_ERR "unable to create proc entry %s\n",
+ ibm->name);
+ ret = -ENODEV;
+ goto err_out;
+ }
+- entry->data = ibm;
+- entry->read_proc = &dispatch_procfs_read;
+- if (ibm->write)
+- entry->write_proc = &dispatch_procfs_write;
+ ibm->flags.proc_created = 1;
+ }
+
--- /dev/null
+From b09c72259e88cec3d602aef987a3209297f3a9c2 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:27 +0000
+Subject: thinkpad-acpi: expose module parameters
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit b09c72259e88cec3d602aef987a3209297f3a9c2 upstream.
+
+Export the normal (non-command) module paramenters as mode 0444, so
+that they will show up in sysfs.
+
+These parameters must not be changed at runtime as a rule, with very
+few exceptions.
+
+Reported-by: Ferenc Wagner <wferi@niif.hu>
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -8126,32 +8126,32 @@ static int __init set_ibm_param(const ch
+ return -EINVAL;
+ }
+
+-module_param(experimental, int, 0);
++module_param(experimental, int, 0444);
+ MODULE_PARM_DESC(experimental,
+ "Enables experimental features when non-zero");
+
+ module_param_named(debug, dbg_level, uint, 0);
+ MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
+
+-module_param(force_load, bool, 0);
++module_param(force_load, bool, 0444);
+ MODULE_PARM_DESC(force_load,
+ "Attempts to load the driver even on a "
+ "mis-identified ThinkPad when true");
+
+-module_param_named(fan_control, fan_control_allowed, bool, 0);
++module_param_named(fan_control, fan_control_allowed, bool, 0444);
+ MODULE_PARM_DESC(fan_control,
+ "Enables setting fan parameters features when true");
+
+-module_param_named(brightness_mode, brightness_mode, uint, 0);
++module_param_named(brightness_mode, brightness_mode, uint, 0444);
+ MODULE_PARM_DESC(brightness_mode,
+ "Selects brightness control strategy: "
+ "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM");
+
+-module_param(brightness_enable, uint, 0);
++module_param(brightness_enable, uint, 0444);
+ MODULE_PARM_DESC(brightness_enable,
+ "Enables backlight control when 1, disables when 0");
+
+-module_param(hotkey_report_mode, uint, 0);
++module_param(hotkey_report_mode, uint, 0444);
+ MODULE_PARM_DESC(hotkey_report_mode,
+ "used for backwards compatibility with userspace, "
+ "see documentation");
+@@ -8174,25 +8174,25 @@ TPACPI_PARAM(volume);
+ TPACPI_PARAM(fan);
+
+ #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+-module_param(dbg_wlswemul, uint, 0);
++module_param(dbg_wlswemul, uint, 0444);
+ MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation");
+ module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0);
+ MODULE_PARM_DESC(wlsw_state,
+ "Initial state of the emulated WLSW switch");
+
+-module_param(dbg_bluetoothemul, uint, 0);
++module_param(dbg_bluetoothemul, uint, 0444);
+ MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation");
+ module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0);
+ MODULE_PARM_DESC(bluetooth_state,
+ "Initial state of the emulated bluetooth switch");
+
+-module_param(dbg_wwanemul, uint, 0);
++module_param(dbg_wwanemul, uint, 0444);
+ MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation");
+ module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0);
+ MODULE_PARM_DESC(wwan_state,
+ "Initial state of the emulated WWAN switch");
+
+-module_param(dbg_uwbemul, uint, 0);
++module_param(dbg_uwbemul, uint, 0444);
+ MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation");
+ module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0);
+ MODULE_PARM_DESC(uwb_state,
--- /dev/null
+From 90765c6aee568137521ba19347c744b5abde8161 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:23 +0000
+Subject: thinkpad-acpi: fix some version quirks
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 90765c6aee568137521ba19347c744b5abde8161 upstream.
+
+Update some of the BIOS/EC version quirks.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -1779,7 +1779,7 @@ static const struct tpacpi_quirk tpacpi_
+
+ TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */
+ TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */
+- TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */
++ TPV_QL1('7', 'E', 'D', '0', '1', '5'), /* R60e, R60i */
+
+ /* BIOS FW BIOS VERS EC FW EC VERS */
+ TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */
+@@ -1795,8 +1795,8 @@ static const struct tpacpi_quirk tpacpi_
+ TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */
+ TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */
+
+- TPV_QL0('7', 'B', 'D', '7'), /* X60/s */
+- TPV_QL0('7', 'J', '3', '0'), /* X60t */
++ TPV_QL1('7', 'B', 'D', '7', '4', '0'), /* X60/s */
++ TPV_QL1('7', 'J', '3', '0', '1', '3'), /* X60t */
+
+ /* (0) - older versions lack DMI EC fw string and functionality */
+ /* (1) - older versions known to lack functionality */
--- /dev/null
+From 347a26860e2293b1347996876d3550499c7bb31f Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:24 +0000
+Subject: thinkpad-acpi: issue backlight class events
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 347a26860e2293b1347996876d3550499c7bb31f upstream.
+
+Take advantage of the new events capabilities of the backlight class to
+notify userspace of backlight changes.
+
+This depends on "backlight: Allow drivers to update the core, and
+generate events on changes", by Matthew Garrett.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Cc: Matthew Garrett <mjg@redhat.com>
+Cc: Richard Purdie <rpurdie@linux.intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+
+---
+ Documentation/laptops/thinkpad-acpi.txt | 51 +++++++-------------------------
+ drivers/platform/x86/thinkpad_acpi.c | 24 ++++++++++++++-
+ 2 files changed, 35 insertions(+), 40 deletions(-)
+
+--- a/Documentation/laptops/thinkpad-acpi.txt
++++ b/Documentation/laptops/thinkpad-acpi.txt
+@@ -460,6 +460,8 @@ event code Key Notes
+ For Lenovo ThinkPads with a new
+ BIOS, it has to be handled either
+ by the ACPI OSI, or by userspace.
++ The driver does the right thing,
++ never mess with this.
+ 0x1011 0x10 FN+END Brightness down. See brightness
+ up for details.
+
+@@ -582,46 +584,15 @@ with hotkey_report_mode.
+
+ Brightness hotkey notes:
+
+-These are the current sane choices for brightness key mapping in
+-thinkpad-acpi:
++Don't mess with the brightness hotkeys in a Thinkpad. If you want
++notifications for OSD, use the sysfs backlight class event support.
+
+-For IBM and Lenovo models *without* ACPI backlight control (the ones on
+-which thinkpad-acpi will autoload its backlight interface by default,
+-and on which ACPI video does not export a backlight interface):
+-
+-1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as
+- these older firmware versions unfortunately won't respect the hotkey
+- mask for brightness keys anyway, and always reacts to them. This
+- usually work fine, unless X.org drivers are doing something to block
+- the BIOS. In that case, use (3) below. This is the default mode of
+- operation.
+-
+-2. Enable the hotkeys, but map them to something else that is NOT
+- KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause
+- userspace to try to change the backlight level, and use that as an
+- on-screen-display hint.
+-
+-3. IF AND ONLY IF X.org drivers find a way to block the firmware from
+- automatically changing the brightness, enable the hotkeys and map
+- them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to
+- something that calls xbacklight. thinkpad-acpi will not be able to
+- change brightness in that case either, so you should disable its
+- backlight interface.
+-
+-For Lenovo models *with* ACPI backlight control:
+-
+-1. Load up ACPI video and use that. ACPI video will report ACPI
+- events for brightness change keys. Do not mess with thinkpad-acpi
+- defaults in this case. thinkpad-acpi should not have anything to do
+- with backlight events in a scenario where ACPI video is loaded:
+- brightness hotkeys must be disabled, and the backlight interface is
+- to be kept disabled as well. This is the default mode of operation.
+-
+-2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi,
+- and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
+- these keys on userspace somehow (e.g. by calling xbacklight).
+- The driver will do this automatically if it detects that ACPI video
+- has been disabled.
++The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events
++automatically for the cases were userspace has to do something to
++implement brightness changes. When you override these events, you will
++either fail to handle properly the ThinkPads that require explicit
++action to change backlight brightness, or the ThinkPads that require
++that no action be taken to work properly.
+
+
+ Bluetooth
+@@ -1465,3 +1436,5 @@ Sysfs interface changelog:
+ and it is always able to disable hot keys. Very old
+ thinkpads are properly supported. hotkey_bios_mask
+ is deprecated and marked for removal.
++
++0x020600: Marker for backlight change event support.
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -22,7 +22,7 @@
+ */
+
+ #define TPACPI_VERSION "0.23"
+-#define TPACPI_SYSFS_VERSION 0x020500
++#define TPACPI_SYSFS_VERSION 0x020600
+
+ /*
+ * Changelog:
+@@ -6083,6 +6083,12 @@ static int brightness_get(struct backlig
+ return status & TP_EC_BACKLIGHT_LVLMSK;
+ }
+
++static void tpacpi_brightness_notify_change(void)
++{
++ backlight_force_update(ibm_backlight_device,
++ BACKLIGHT_UPDATE_HOTKEY);
++}
++
+ static struct backlight_ops ibm_backlight_data = {
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+@@ -6237,6 +6243,12 @@ static int __init brightness_init(struct
+ ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
+ backlight_update_status(ibm_backlight_device);
+
++ vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
++ "brightness: registering brightness hotkeys "
++ "as change notification\n");
++ tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
++ | TP_ACPI_HKEY_BRGHTUP_MASK
++ | TP_ACPI_HKEY_BRGHTDWN_MASK);;
+ return 0;
+ }
+
+@@ -6313,6 +6325,9 @@ static int brightness_write(char *buf)
+ * Doing it this way makes the syscall restartable in case of EINTR
+ */
+ rc = brightness_set(level);
++ if (!rc && ibm_backlight_device)
++ backlight_force_update(ibm_backlight_device,
++ BACKLIGHT_UPDATE_SYSFS);
+ return (rc == -EINTR)? -ERESTARTSYS : rc;
+ }
+
+@@ -7712,6 +7727,13 @@ static struct ibm_struct fan_driver_data
+ */
+ static void tpacpi_driver_event(const unsigned int hkey_event)
+ {
++ if (ibm_backlight_device) {
++ switch (hkey_event) {
++ case TP_HKEY_EV_BRGHT_UP:
++ case TP_HKEY_EV_BRGHT_DOWN:
++ tpacpi_brightness_notify_change();
++ }
++ }
+ }
+
+
--- /dev/null
+From b525c06cdbd8a3963f0173ccd23f9147d4c384b5 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Thu, 25 Feb 2010 22:22:22 -0300
+Subject: thinkpad-acpi: lock down video output state access
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit b525c06cdbd8a3963f0173ccd23f9147d4c384b5 upstream.
+
+Given the right combination of ThinkPad and X.org, just reading the
+video output control state is enough to hard-crash X.org.
+
+Until the day I somehow find out a model or BIOS cut date to not
+provide this feature to ThinkPads that can do video switching through
+X RandR, change permissions so that only processes with CAP_SYS_ADMIN
+can access any sort of video output control state.
+
+This bug could be considered a local DoS I suppose, as it allows any
+non-privledged local user to cause some versions of X.org to
+hard-crash some ThinkPads.
+
+Reported-by: Jidanni <jidanni@jidanni.org>
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/laptops/thinkpad-acpi.txt | 4 ++++
+ drivers/platform/x86/Kconfig | 10 ++++++++--
+ drivers/platform/x86/thinkpad_acpi.c | 15 +++++++++++++--
+ 3 files changed, 25 insertions(+), 4 deletions(-)
+
+--- a/Documentation/laptops/thinkpad-acpi.txt
++++ b/Documentation/laptops/thinkpad-acpi.txt
+@@ -650,6 +650,10 @@ LCD, CRT or DVI (if available). The foll
+ echo expand_toggle > /proc/acpi/ibm/video
+ echo video_switch > /proc/acpi/ibm/video
+
++NOTE: Access to this feature is restricted to processes owning the
++CAP_SYS_ADMIN capability for safety reasons, as it can interact badly
++enough with some versions of X.org to crash it.
++
+ Each video output device can be enabled or disabled individually.
+ Reading /proc/acpi/ibm/video shows the status of each device.
+
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -291,9 +291,15 @@ config THINKPAD_ACPI_VIDEO
+ server running, phase of the moon, and the current mood of
+ Schroedinger's cat. If you can use X.org's RandR to control
+ your ThinkPad's video output ports instead of this feature,
+- don't think twice: do it and say N here to save some memory.
++ don't think twice: do it and say N here to save memory and avoid
++ bad interactions with X.org.
+
+- If you are not sure, say Y here.
++ NOTE: access to this feature is limited to processes with the
++ CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms
++ where it interacts badly with X.org.
++
++ If you are not sure, say Y here but do try to check if you could
++ be using X.org RandR instead.
+
+ config THINKPAD_ACPI_HOTKEY_POLL
+ bool "Support NVRAM polling for hot keys"
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -281,6 +281,7 @@ struct ibm_init_struct {
+ char param[32];
+
+ int (*init) (struct ibm_init_struct *);
++ mode_t base_procfs_mode;
+ struct ibm_struct *data;
+ };
+
+@@ -4620,6 +4621,10 @@ static int video_read(struct seq_file *m
+ return 0;
+ }
+
++ /* Even reads can crash X.org, so... */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
+ status = video_outputsw_get();
+ if (status < 0)
+ return status;
+@@ -4653,6 +4658,10 @@ static int video_write(char *buf)
+ if (video_supported == TPACPI_VIDEO_NONE)
+ return -ENODEV;
+
++ /* Even reads can crash X.org, let alone writes... */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
+ enable = 0;
+ disable = 0;
+
+@@ -7887,9 +7896,10 @@ static int __init ibm_init(struct ibm_in
+ "%s installed\n", ibm->name);
+
+ if (ibm->read) {
+- mode_t mode;
++ mode_t mode = iibm->base_procfs_mode;
+
+- mode = S_IRUGO;
++ if (!mode)
++ mode = S_IRUGO;
+ if (ibm->write)
+ mode |= S_IWUSR;
+ entry = proc_create_data(ibm->name, mode, proc_dir,
+@@ -8080,6 +8090,7 @@ static struct ibm_init_struct ibms_init[
+ #ifdef CONFIG_THINKPAD_ACPI_VIDEO
+ {
+ .init = video_init,
++ .base_procfs_mode = S_IRUSR,
+ .data = &video_driver_data,
+ },
+ #endif
--- /dev/null
+From 5451a923bbdcff6ae665947e120af7238b21a9d2 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Tue, 15 Dec 2009 21:51:07 -0200
+Subject: thinkpad-acpi: log initial state of rfkill switches
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 5451a923bbdcff6ae665947e120af7238b21a9d2 upstream.
+
+We already log the initial state of the hardware rfkill switch (WLSW),
+might as well log the state of the softswitches as well.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Cc: Josip Rodin <joy+kernel@entuzijast.net>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -1264,6 +1264,7 @@ static int __init tpacpi_new_rfkill(cons
+ struct tpacpi_rfk *atp_rfk;
+ int res;
+ bool sw_state = false;
++ bool hw_state;
+ int sw_status;
+
+ BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
+@@ -1298,7 +1299,8 @@ static int __init tpacpi_new_rfkill(cons
+ rfkill_init_sw_state(atp_rfk->rfkill, sw_state);
+ }
+ }
+- rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state());
++ hw_state = tpacpi_rfk_check_hwblock_state();
++ rfkill_set_hw_state(atp_rfk->rfkill, hw_state);
+
+ res = rfkill_register(atp_rfk->rfkill);
+ if (res < 0) {
+@@ -1311,6 +1313,9 @@ static int __init tpacpi_new_rfkill(cons
+ }
+
+ tpacpi_rfkill_switches[id] = atp_rfk;
++
++ printk(TPACPI_INFO "rfkill switch %s: radio is %sblocked\n",
++ name, (sw_state || hw_state) ? "" : "un");
+ return 0;
+ }
+
--- /dev/null
+From 9ebd9e833648745fa5ac6998b9e0153ccd3ba839 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:28 +0000
+Subject: thinkpad-acpi: log temperatures on termal alarm (v2)
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 9ebd9e833648745fa5ac6998b9e0153ccd3ba839 upstream.
+
+Log temperatures on any of the EC thermal alarms. It could be
+useful to help tracking down what is happening...
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Acked-by: Pavel Machek <pavel@ucw.cz>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 57 +++++++++++++++++++++++++++--------
+ 1 file changed, 45 insertions(+), 12 deletions(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -3548,49 +3548,57 @@ static bool hotkey_notify_usrevent(const
+ }
+ }
+
++static void thermal_dump_all_sensors(void);
++
+ static bool hotkey_notify_thermal(const u32 hkey,
+ bool *send_acpi_ev,
+ bool *ignore_acpi_ev)
+ {
++ bool known = true;
++
+ /* 0x6000-0x6FFF: thermal alarms */
+ *send_acpi_ev = true;
+ *ignore_acpi_ev = false;
+
+ switch (hkey) {
++ case TP_HKEY_EV_THM_TABLE_CHANGED:
++ printk(TPACPI_INFO
++ "EC reports that Thermal Table has changed\n");
++ /* recommended action: do nothing, we don't have
++ * Lenovo ATM information */
++ return true;
+ case TP_HKEY_EV_ALARM_BAT_HOT:
+ printk(TPACPI_CRIT
+ "THERMAL ALARM: battery is too hot!\n");
+ /* recommended action: warn user through gui */
+- return true;
++ break;
+ case TP_HKEY_EV_ALARM_BAT_XHOT:
+ printk(TPACPI_ALERT
+ "THERMAL EMERGENCY: battery is extremely hot!\n");
+ /* recommended action: immediate sleep/hibernate */
+- return true;
++ break;
+ case TP_HKEY_EV_ALARM_SENSOR_HOT:
+ printk(TPACPI_CRIT
+ "THERMAL ALARM: "
+ "a sensor reports something is too hot!\n");
+ /* recommended action: warn user through gui, that */
+ /* some internal component is too hot */
+- return true;
++ break;
+ case TP_HKEY_EV_ALARM_SENSOR_XHOT:
+ printk(TPACPI_ALERT
+ "THERMAL EMERGENCY: "
+ "a sensor reports something is extremely hot!\n");
+ /* recommended action: immediate sleep/hibernate */
+- return true;
+- case TP_HKEY_EV_THM_TABLE_CHANGED:
+- printk(TPACPI_INFO
+- "EC reports that Thermal Table has changed\n");
+- /* recommended action: do nothing, we don't have
+- * Lenovo ATM information */
+- return true;
++ break;
+ default:
+ printk(TPACPI_ALERT
+ "THERMAL ALERT: unknown thermal alarm received\n");
+- return false;
++ known = false;
+ }
++
++ thermal_dump_all_sensors();
++
++ return known;
+ }
+
+ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+@@ -5472,8 +5480,11 @@ enum { /* TPACPI_THERMAL_TPEC_* */
+ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
+ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
+ TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
++
++ TPACPI_THERMAL_SENSOR_NA = -128000, /* Sensor not available */
+ };
+
++
+ #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
+ struct ibm_thermal_sensors_struct {
+ s32 temp[TPACPI_MAX_THERMAL_SENSORS];
+@@ -5563,6 +5574,28 @@ static int thermal_get_sensors(struct ib
+ return n;
+ }
+
++static void thermal_dump_all_sensors(void)
++{
++ int n, i;
++ struct ibm_thermal_sensors_struct t;
++
++ n = thermal_get_sensors(&t);
++ if (n <= 0)
++ return;
++
++ printk(TPACPI_NOTICE
++ "temperatures (Celsius):");
++
++ for (i = 0; i < n; i++) {
++ if (t.temp[i] != TPACPI_THERMAL_SENSOR_NA)
++ printk(KERN_CONT " %d", (int)(t.temp[i] / 1000));
++ else
++ printk(KERN_CONT " N/A");
++ }
++
++ printk(KERN_CONT "\n");
++}
++
+ /* sysfs temp##_input -------------------------------------------------- */
+
+ static ssize_t thermal_temp_input_show(struct device *dev,
+@@ -5578,7 +5611,7 @@ static ssize_t thermal_temp_input_show(s
+ res = thermal_get_sensor(idx, &value);
+ if (res)
+ return res;
+- if (value == TP_EC_THERMAL_TMP_NA * 1000)
++ if (value == TPACPI_THERMAL_SENSOR_NA)
+ return -ENXIO;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
--- /dev/null
+From 6b30eb7d211840ba1a03f855d9e7b80a921368f2 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:25 +0000
+Subject: thinkpad-acpi: silence bogus complain during rmmod
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 6b30eb7d211840ba1a03f855d9e7b80a921368f2 upstream.
+
+Fix this bogus warning during module shutdown, when
+backlight event reporting is enabled:
+
+"thinkpad_acpi: required events 0x00018000 not enabled!"
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -2190,7 +2190,8 @@ static int hotkey_mask_set(u32 mask)
+ fwmask, hotkey_acpi_mask);
+ }
+
+- hotkey_mask_warn_incomplete_mask();
++ if (tpacpi_lifecycle != TPACPI_LIFE_EXITING)
++ hotkey_mask_warn_incomplete_mask();
+
+ return rc;
+ }
--- /dev/null
+From d89a727aff649f6768f7a34ee57f031ebf8bab4c Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Tue, 15 Dec 2009 21:51:06 -0200
+Subject: thinkpad-acpi: sync input device EV_SW initial state
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit d89a727aff649f6768f7a34ee57f031ebf8bab4c upstream.
+
+Before we register the input device, sync the input layer EV_SW state
+through a call to input_report_switch(), to avoid issuing a gratuitous
+event for the initial state of these switches.
+
+This fixes some annoyances caused by the interaction with rfkill and
+EV_SW SW_RFKILL_ALL events.
+
+Reported-by: Kevin Locke <kevin@kevinlocke.name>
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Cc: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+Cc: Johannes Berg <johannes@sipsolutions.net>
+Cc: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -3188,6 +3188,8 @@ static int __init hotkey_init(struct ibm
+ int res, i;
+ int status;
+ int hkeyv;
++ bool radiosw_state = false;
++ bool tabletsw_state = false;
+
+ unsigned long quirks;
+
+@@ -3293,6 +3295,7 @@ static int __init hotkey_init(struct ibm
+ #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_wlswemul) {
+ tp_features.hotkey_wlsw = 1;
++ radiosw_state = !!tpacpi_wlsw_emulstate;
+ printk(TPACPI_INFO
+ "radio switch emulation enabled\n");
+ } else
+@@ -3300,6 +3303,7 @@ static int __init hotkey_init(struct ibm
+ /* Not all thinkpads have a hardware radio switch */
+ if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+ tp_features.hotkey_wlsw = 1;
++ radiosw_state = !!status;
+ printk(TPACPI_INFO
+ "radio switch found; radios are %s\n",
+ enabled(status, 0));
+@@ -3311,11 +3315,11 @@ static int __init hotkey_init(struct ibm
+ /* For X41t, X60t, X61t Tablets... */
+ if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
+ tp_features.hotkey_tablet = 1;
++ tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK);
+ printk(TPACPI_INFO
+ "possible tablet mode switch found; "
+ "ThinkPad in %s mode\n",
+- (status & TP_HOTKEY_TABLET_MASK)?
+- "tablet" : "laptop");
++ (tabletsw_state) ? "tablet" : "laptop");
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_tablet_mode.attr);
+ }
+@@ -3366,9 +3370,13 @@ static int __init hotkey_init(struct ibm
+
+ if (tp_features.hotkey_wlsw) {
+ input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL);
++ input_report_switch(tpacpi_inputdev,
++ SW_RFKILL_ALL, radiosw_state);
+ }
+ if (tp_features.hotkey_tablet) {
+ input_set_capability(tpacpi_inputdev, EV_SW, SW_TABLET_MODE);
++ input_report_switch(tpacpi_inputdev,
++ SW_TABLET_MODE, tabletsw_state);
+ }
+
+ /* Do not issue duplicate brightness change events to
+@@ -3435,8 +3443,6 @@ static int __init hotkey_init(struct ibm
+ tpacpi_inputdev->close = &hotkey_inputdev_close;
+
+ hotkey_poll_setup_safe(true);
+- tpacpi_send_radiosw_update();
+- tpacpi_input_send_tabletsw();
+
+ return 0;
+
--- /dev/null
+From 792979c8032b8f5adb77ea986db7082fff04c8e7 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Wed, 9 Dec 2009 01:36:29 +0000
+Subject: thinkpad-acpi: use input_set_capability
+
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+
+commit 792979c8032b8f5adb77ea986db7082fff04c8e7 upstream.
+
+Use input_set_capability() instead of set_bit.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Cc: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/thinkpad_acpi.c | 14 +++++---------
+ 1 file changed, 5 insertions(+), 9 deletions(-)
+
+--- a/drivers/platform/x86/thinkpad_acpi.c
++++ b/drivers/platform/x86/thinkpad_acpi.c
+@@ -3350,16 +3350,14 @@ static int __init hotkey_init(struct ibm
+ TPACPI_HOTKEY_MAP_SIZE);
+ }
+
+- set_bit(EV_KEY, tpacpi_inputdev->evbit);
+- set_bit(EV_MSC, tpacpi_inputdev->evbit);
+- set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
++ input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN);
+ tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+ tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+ tpacpi_inputdev->keycode = hotkey_keycode_map;
+ for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+ if (hotkey_keycode_map[i] != KEY_RESERVED) {
+- set_bit(hotkey_keycode_map[i],
+- tpacpi_inputdev->keybit);
++ input_set_capability(tpacpi_inputdev, EV_KEY,
++ hotkey_keycode_map[i]);
+ } else {
+ if (i < sizeof(hotkey_reserved_mask)*8)
+ hotkey_reserved_mask |= 1 << i;
+@@ -3367,12 +3365,10 @@ static int __init hotkey_init(struct ibm
+ }
+
+ if (tp_features.hotkey_wlsw) {
+- set_bit(EV_SW, tpacpi_inputdev->evbit);
+- set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit);
++ input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL);
+ }
+ if (tp_features.hotkey_tablet) {
+- set_bit(EV_SW, tpacpi_inputdev->evbit);
+- set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
++ input_set_capability(tpacpi_inputdev, EV_SW, SW_TABLET_MODE);
+ }
+
+ /* Do not issue duplicate brightness change events to
--- /dev/null
+From 9d260ebc09a0ad6b5c73e17676df42c7bc75ff64 Mon Sep 17 00:00:00 2001
+From: Andreas Herrmann <herrmann.der.user@googlemail.com>
+Date: Wed, 16 Dec 2009 15:43:55 +0100
+Subject: x86, amd: Get multi-node CPU info from NodeId MSR instead of PCI config space
+
+From: Andreas Herrmann <herrmann.der.user@googlemail.com>
+
+commit 9d260ebc09a0ad6b5c73e17676df42c7bc75ff64 upstream.
+
+Use NodeId MSR to get NodeId and number of nodes per processor.
+
+Signed-off-by: Andreas Herrmann <andreas.herrmann3@amd.com>
+LKML-Reference: <20091216144355.GB28798@alberich.amd.com>
+Signed-off-by: H. Peter Anvin <hpa@zytor.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/include/asm/cpufeature.h | 1
+ arch/x86/include/asm/msr-index.h | 1
+ arch/x86/kernel/cpu/amd.c | 53 ++++++++++----------------------------
+ 3 files changed, 17 insertions(+), 38 deletions(-)
+
+--- a/arch/x86/include/asm/cpufeature.h
++++ b/arch/x86/include/asm/cpufeature.h
+@@ -153,6 +153,7 @@
+ #define X86_FEATURE_SSE5 (6*32+11) /* SSE-5 */
+ #define X86_FEATURE_SKINIT (6*32+12) /* SKINIT/STGI instructions */
+ #define X86_FEATURE_WDT (6*32+13) /* Watchdog timer */
++#define X86_FEATURE_NODEID_MSR (6*32+19) /* NodeId MSR */
+
+ /*
+ * Auxiliary flags: Linux defined - For features scattered in various
+--- a/arch/x86/include/asm/msr-index.h
++++ b/arch/x86/include/asm/msr-index.h
+@@ -125,6 +125,7 @@
+ #define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2
+ #define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff
+ #define FAM10H_MMIO_CONF_BASE_SHIFT 20
++#define MSR_FAM10H_NODE_ID 0xc001100c
+
+ /* K8 MSRs */
+ #define MSR_K8_TOP_MEM1 0xc001001a
+--- a/arch/x86/kernel/cpu/amd.c
++++ b/arch/x86/kernel/cpu/amd.c
+@@ -254,59 +254,36 @@ static int __cpuinit nearby_node(int api
+
+ /*
+ * Fixup core topology information for AMD multi-node processors.
+- * Assumption 1: Number of cores in each internal node is the same.
+- * Assumption 2: Mixed systems with both single-node and dual-node
+- * processors are not supported.
++ * Assumption: Number of cores in each internal node is the same.
+ */
+ #ifdef CONFIG_X86_HT
+ static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c)
+ {
+-#ifdef CONFIG_PCI
+- u32 t, cpn;
+- u8 n, n_id;
++ unsigned long long value;
++ u32 nodes, cores_per_node;
+ int cpu = smp_processor_id();
+
++ if (!cpu_has(c, X86_FEATURE_NODEID_MSR))
++ return;
++
+ /* fixup topology information only once for a core */
+ if (cpu_has(c, X86_FEATURE_AMD_DCM))
+ return;
+
+- /* check for multi-node processor on boot cpu */
+- t = read_pci_config(0, 24, 3, 0xe8);
+- if (!(t & (1 << 29)))
++ rdmsrl(MSR_FAM10H_NODE_ID, value);
++
++ nodes = ((value >> 3) & 7) + 1;
++ if (nodes == 1)
+ return;
+
+ set_cpu_cap(c, X86_FEATURE_AMD_DCM);
++ cores_per_node = c->x86_max_cores / nodes;
+
+- /* cores per node: each internal node has half the number of cores */
+- cpn = c->x86_max_cores >> 1;
+-
+- /* even-numbered NB_id of this dual-node processor */
+- n = c->phys_proc_id << 1;
++ /* store NodeID, use llc_shared_map to store sibling info */
++ per_cpu(cpu_llc_id, cpu) = value & 7;
+
+- /*
+- * determine internal node id and assign cores fifty-fifty to
+- * each node of the dual-node processor
+- */
+- t = read_pci_config(0, 24 + n, 3, 0xe8);
+- n = (t>>30) & 0x3;
+- if (n == 0) {
+- if (c->cpu_core_id < cpn)
+- n_id = 0;
+- else
+- n_id = 1;
+- } else {
+- if (c->cpu_core_id < cpn)
+- n_id = 1;
+- else
+- n_id = 0;
+- }
+-
+- /* compute entire NodeID, use llc_shared_map to store sibling info */
+- per_cpu(cpu_llc_id, cpu) = (c->phys_proc_id << 1) + n_id;
+-
+- /* fixup core id to be in range from 0 to cpn */
+- c->cpu_core_id = c->cpu_core_id % cpn;
+-#endif
++ /* fixup core id to be in range from 0 to (cores_per_node - 1) */
++ c->cpu_core_id = c->cpu_core_id % cores_per_node;
+ }
+ #endif
+