[PATCH] Skip selftest in some Asus laptops

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch was already picked up for 4.9, but it can help a lot of users
in the meantime.

Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@xxxxxxxxx>
---
 PatchList.txt                          |   1 +
 i8042-skip-selftest-asus-laptops.patch | 373 +++++++++++++++++++++++++++++++++
 kernel.spec                            |   2 +
 3 files changed, 376 insertions(+)
 create mode 100644 i8042-skip-selftest-asus-laptops.patch

diff --git a/PatchList.txt b/PatchList.txt
index 3a7fd73..3cce44a 100644
--- a/PatchList.txt
+++ b/PatchList.txt
@@ -76,3 +76,4 @@ firmware-Drop-WARN-from-usermodehelper_read_trylock-.patch
 
 drm-i915-turn-off-wc-mmaps.patch
 
+i8042-skip-selftest-asus-laptops.patch
diff --git a/i8042-skip-selftest-asus-laptops.patch b/i8042-skip-selftest-asus-laptops.patch
new file mode 100644
index 0000000..351556e
--- /dev/null
+++ b/i8042-skip-selftest-asus-laptops.patch
@@ -0,0 +1,373 @@
+From 930e19248e9b61da36c967687ca79c4d5f977919 Mon Sep 17 00:00:00 2001
+From: Marcos Paulo de Souza <marcos.souza.org@xxxxxxxxx>
+Date: Sat, 1 Oct 2016 12:07:35 -0700
+Subject: Input: i8042 - skip selftest on ASUS laptops
+
+On suspend/resume cycle, selftest is executed to reset i8042 controller.
+But when this is done in Asus devices, subsequent calls to detect/init
+functions to elantech driver fails. Skipping selftest fixes this problem.
+
+An easier step to reproduce this problem is adding i8042.reset=1 as a
+kernel parameter. On Asus laptops, it'll make the system to start with the
+touchpad already stuck, since psmouse_probe forcibly calls the selftest
+function.
+
+This patch was inspired by John Hiesey's change[1], but, since this problem
+affects a lot of models of Asus, let's avoid running selftests on them.
+
+All models affected by this problem:
+A455LD
+K401LB
+K501LB
+K501LX
+R409L
+V502LX
+X302LA
+X450LCP
+X450LD
+X455LAB
+X455LDB
+X455LF
+Z450LA
+
+[1]: https://marc.info/?l=linux-input&m=144312209020616&w=2
+
+Fixes: "ETPS/2 Elantech Touchpad dies after resume from suspend"
+(https://bugzilla.kernel.org/show_bug.cgi?id=107971)
+
+Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@xxxxxxxxx>
+Cc: stable@xxxxxxxxxxxxxxx
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
+---
+ Documentation/kernel-parameters.txt     |  9 +++-
+ drivers/input/serio/i8042-io.h          |  2 +-
+ drivers/input/serio/i8042-ip22io.h      |  2 +-
+ drivers/input/serio/i8042-ppcio.h       |  2 +-
+ drivers/input/serio/i8042-sparcio.h     |  2 +-
+ drivers/input/serio/i8042-unicore32io.h |  2 +-
+ drivers/input/serio/i8042-x86ia64io.h   | 96 +++++++++++++++++++++++++++++++--
+ drivers/input/serio/i8042.c             | 55 +++++++++++++++----
+ 8 files changed, 150 insertions(+), 20 deletions(-)
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 0b3de80..3475b32 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1409,7 +1409,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ 	i8042.nopnp	[HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
+ 			     controllers
+ 	i8042.notimeout	[HW] Ignore timeout condition signalled by controller
+-	i8042.reset	[HW] Reset the controller during init and cleanup
++	i8042.reset	[HW] Reset the controller during init, cleanup and
++			     suspend-to-ram transitions, only during s2r
++			     transitions, or never reset
++			Format: { 1 | Y | y | 0 | N | n }
++			1, Y, y: always reset controller
++			0, N, n: don't ever reset controller
++			Default: only on s2r transitions on x86; most other
++			architectures force reset to be always executed
+ 	i8042.unlock	[HW] Unlock (ignore) the keylock
+ 	i8042.kbdreset  [HW] Reset device connected to KBD port
+ 
+diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
+index a5eed2a..34da81c 100644
+--- a/drivers/input/serio/i8042-io.h
++++ b/drivers/input/serio/i8042-io.h
+@@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
+ 		return -EBUSY;
+ #endif
+ 
+-	i8042_reset = 1;
++	i8042_reset = I8042_RESET_ALWAYS;
+ 	return 0;
+ }
+ 
+diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
+index ee1ad27..08a1c10 100644
+--- a/drivers/input/serio/i8042-ip22io.h
++++ b/drivers/input/serio/i8042-ip22io.h
+@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
+ 		return -EBUSY;
+ #endif
+ 
+-	i8042_reset = 1;
++	i8042_reset = I8042_RESET_ALWAYS;
+ 
+ 	return 0;
+ }
+diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
+index f708c75..1aabea4 100644
+--- a/drivers/input/serio/i8042-ppcio.h
++++ b/drivers/input/serio/i8042-ppcio.h
+@@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
+ 
+ static inline int i8042_platform_init(void)
+ {
+-	i8042_reset = 1;
++	i8042_reset = I8042_RESET_ALWAYS;
+ 	return 0;
+ }
+ 
+diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
+index afcd1c1..6231d63 100644
+--- a/drivers/input/serio/i8042-sparcio.h
++++ b/drivers/input/serio/i8042-sparcio.h
+@@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
+ 		}
+ 	}
+ 
+-	i8042_reset = 1;
++	i8042_reset = I8042_RESET_ALWAYS;
+ 
+ 	return 0;
+ }
+diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
+index 73f5cc1..4557475 100644
+--- a/drivers/input/serio/i8042-unicore32io.h
++++ b/drivers/input/serio/i8042-unicore32io.h
+@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
+ 	if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
+ 		return -EBUSY;
+ 
+-	i8042_reset = 1;
++	i8042_reset = I8042_RESET_ALWAYS;
+ 	return 0;
+ }
+ 
+diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
+index 68f5f4a..f4bfb4b 100644
+--- a/drivers/input/serio/i8042-x86ia64io.h
++++ b/drivers/input/serio/i8042-x86ia64io.h
+@@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
+ 	{ }
+ };
+ 
++/*
++ * On some Asus laptops, just running self tests cause problems.
++ */
++static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
++		},
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++			DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
++		},
++	},
++	{ }
++};
+ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
+ 	{
+ 		/* MSI Wind U-100 */
+@@ -1072,12 +1156,18 @@ static int __init i8042_platform_init(void)
+ 		return retval;
+ 
+ #if defined(__ia64__)
+-        i8042_reset = true;
++        i8042_reset = I8042_RESET_ALWAYS;
+ #endif
+ 
+ #ifdef CONFIG_X86
+-	if (dmi_check_system(i8042_dmi_reset_table))
+-		i8042_reset = true;
++	/* Honor module parameter when value is not default */
++	if (i8042_reset == I8042_RESET_DEFAULT) {
++		if (dmi_check_system(i8042_dmi_reset_table))
++			i8042_reset = I8042_RESET_ALWAYS;
++
++		if (dmi_check_system(i8042_dmi_noselftest_table))
++			i8042_reset = I8042_RESET_NEVER;
++	}
+ 
+ 	if (dmi_check_system(i8042_dmi_noloop_table))
+ 		i8042_noloop = true;
+diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
+index b4d3408..674a760 100644
+--- a/drivers/input/serio/i8042.c
++++ b/drivers/input/serio/i8042.c
+@@ -48,9 +48,39 @@ static bool i8042_unlock;
+ module_param_named(unlock, i8042_unlock, bool, 0);
+ MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
+ 
+-static bool i8042_reset;
+-module_param_named(reset, i8042_reset, bool, 0);
+-MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
++enum i8042_controller_reset_mode {
++	I8042_RESET_NEVER,
++	I8042_RESET_ALWAYS,
++	I8042_RESET_ON_S2RAM,
++#define I8042_RESET_DEFAULT	I8042_RESET_ON_S2RAM
++};
++static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
++static int i8042_set_reset(const char *val, const struct kernel_param *kp)
++{
++	enum i8042_controller_reset_mode *arg = kp->arg;
++	int error;
++	bool reset;
++
++	if (val) {
++		error = kstrtobool(val, &reset);
++		if (error)
++			return error;
++	} else {
++		reset = true;
++	}
++
++	*arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
++	return 0;
++}
++
++static const struct kernel_param_ops param_ops_reset_param = {
++	.flags = KERNEL_PARAM_OPS_FL_NOARG,
++	.set = i8042_set_reset,
++};
++#define param_check_reset_param(name, p)	\
++	__param_check(name, p, enum i8042_controller_reset_mode)
++module_param_named(reset, i8042_reset, reset_param, 0);
++MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
+ 
+ static bool i8042_direct;
+ module_param_named(direct, i8042_direct, bool, 0);
+@@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
+  * Reset the controller and reset CRT to the original value set by BIOS.
+  */
+ 
+-static void i8042_controller_reset(bool force_reset)
++static void i8042_controller_reset(bool s2r_wants_reset)
+ {
+ 	i8042_flush();
+ 
+@@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
+  * Reset the controller if requested.
+  */
+ 
+-	if (i8042_reset || force_reset)
++	if (i8042_reset == I8042_RESET_ALWAYS ||
++	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
+ 		i8042_controller_selftest();
++	}
+ 
+ /*
+  * Restore the original control register setting.
+@@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
+  * before suspending.
+  */
+ 
+-static int i8042_controller_resume(bool force_reset)
++static int i8042_controller_resume(bool s2r_wants_reset)
+ {
+ 	int error;
+ 
+@@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
+ 	if (error)
+ 		return error;
+ 
+-	if (i8042_reset || force_reset) {
++	if (i8042_reset == I8042_RESET_ALWAYS ||
++	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
+ 		error = i8042_controller_selftest();
+ 		if (error)
+ 			return error;
+@@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
+ 
+ static int i8042_pm_resume(struct device *dev)
+ {
+-	bool force_reset;
++	bool want_reset;
+ 	int i;
+ 
+ 	for (i = 0; i < I8042_NUM_PORTS; i++) {
+@@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
+ 	 * off control to the platform firmware, otherwise we can simply restore
+ 	 * the mode.
+ 	 */
+-	force_reset = pm_resume_via_firmware();
++	want_reset = pm_resume_via_firmware();
+ 
+-	return i8042_controller_resume(force_reset);
++	return i8042_controller_resume(want_reset);
+ }
+ 
+ static int i8042_pm_thaw(struct device *dev)
+@@ -1481,7 +1514,7 @@ static int __init i8042_probe(struct platform_device *dev)
+ 
+ 	i8042_platform_device = dev;
+ 
+-	if (i8042_reset) {
++	if (i8042_reset == I8042_RESET_ALWAYS) {
+ 		error = i8042_controller_selftest();
+ 		if (error)
+ 			return error;
+-- 
+cgit v0.12
+
diff --git a/kernel.spec b/kernel.spec
index b54e34f..00ffcd9 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -593,6 +593,8 @@ Patch502: firmware-Drop-WARN-from-usermodehelper_read_trylock-.patch
 
 # Patch503: drm-i915-turn-off-wc-mmaps.patch
 
+Patch504: i8042-skip-selftest-asus-laptops.patch
+
 Patch508: kexec-uefi-copy-secure_boot-flag-in-boot-params.patch
 
 #CVE-2016-3134 rhbz 1317383 1317384
-- 
2.7.4
_______________________________________________
kernel mailing list -- kernel@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to kernel-leave@xxxxxxxxxxxxxxxxxxxxxxx




[Index of Archives]     [Fedora General Discussion]     [Older Fedora Users Archive]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Legacy]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Announce]     [Fedora Package Review]     [Fedora Music]     [Fedora Packaging]     [Centos]     [Fedora SELinux]     [Coolkey]     [Yum Users]     [Tux]     [Yosemite News]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [USB]     [Asterisk PBX]

  Powered by Linux