linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Avoid selftests on some Asus models
@ 2016-09-25 13:25 Marcos Paulo de Souza
  2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-09-25 13:25 UTC (permalink / raw)
  To: dmitry.torokhov, linux-input, linux-kernel; +Cc: Marcos Paulo de Souza

Hi guys,

this is my forth iteration in this patch. I hope now this address all problems
and, at least, most Asus models affect by this problem.

All models affected by this problem:
A455LD
K401LB
K501LB
K501LX
R409L
V502LX
X302LA
X450LCP
X450LD
X455LAB
X455LDB
X455LF
Z450LA

Changes since v3:
Add back all Asus models, instead of the dump decision of avoiding selftests in 
all Asus laptops

Changes since v2:
Avoid selftest in all Asus laptops

Changes since v1:
Change kernel parameter i8042.reset to accept different values, instead of creating
a new kernel parameter.

Please let me know if there is something that needs more polishment.

Thanks!

Marcos Paulo de Souza (2):
  input/serio/i8042.c: Skipt selftest on ASUS laptops
  kernel-parameters: Update i8042.reset parameter documentation

 Documentation/kernel-parameters.txt   |  7 ++-
 drivers/input/serio/i8042-x86ia64io.h | 94 ++++++++++++++++++++++++++++++++++-
 drivers/input/serio/i8042.c           | 38 +++++++++++---
 3 files changed, 130 insertions(+), 9 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops
  2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
@ 2016-09-25 13:25 ` Marcos Paulo de Souza
  2016-09-25 13:25 ` [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation Marcos Paulo de Souza
  2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
  2 siblings, 0 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-09-25 13:25 UTC (permalink / raw)
  To: dmitry.torokhov, linux-input, linux-kernel; +Cc: Marcos Paulo de Souza

On suspend/resume cycle, selftest is executed to reset i8042 controller.
But when this is done in Asus devices, posterior 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@gmail.com>
---
 drivers/input/serio/i8042-x86ia64io.h | 94 ++++++++++++++++++++++++++++++++++-
 drivers/input/serio/i8042.c           | 39 ++++++++++++---
 2 files changed, 125 insertions(+), 8 deletions(-)

diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 68f5f4a..0d96539 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 */
@@ -1076,8 +1160,14 @@ static int __init i8042_platform_init(void)
 #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_ON_RESUME) {
+		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 405252a..c0e76c2 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -48,9 +48,33 @@ 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_RESUME
+};
+static unsigned int i8042_reset = I8042_RESET_ON_RESUME;
+static int i8042_set_reset(const char *val, const struct kernel_param *kp)
+{
+	unsigned int ret = I8042_RESET_ON_RESUME;
+
+	if (!val || !strncmp(val, "1", 1) || !strncasecmp(val, "y", 1))
+		ret = I8042_RESET_ALWAYS;
+	else if (!strncmp(val, "0", 1) || !strncasecmp(val, "n", 1))
+		ret = I8042_RESET_NEVER;
+
+	*((unsigned int *)kp->arg) = ret;
+
+	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, unsigned int)
+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);
@@ -890,6 +914,9 @@ static int i8042_controller_selftest(void)
 	unsigned char param;
 	int i = 0;
 
+	if (i8042_reset == I8042_RESET_NEVER)
+		return 0;
+
 	/*
 	 * We try this 5 times; on some really fragile systems this does not
 	 * take the first time...
@@ -1044,7 +1071,7 @@ static void i8042_controller_reset(bool force_reset)
  * Reset the controller if requested.
  */
 
-	if (i8042_reset || force_reset)
+	if (i8042_reset != I8042_RESET_NEVER || force_reset)
 		i8042_controller_selftest();
 
 /*
@@ -1118,7 +1145,7 @@ static int i8042_controller_resume(bool force_reset)
 	if (error)
 		return error;
 
-	if (i8042_reset || force_reset) {
+	if (i8042_reset != I8042_RESET_NEVER || force_reset) {
 		error = i8042_controller_selftest();
 		if (error)
 			return error;
@@ -1482,7 +1509,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;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation
  2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
  2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
@ 2016-09-25 13:25 ` Marcos Paulo de Souza
  2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
  2 siblings, 0 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-09-25 13:25 UTC (permalink / raw)
  To: dmitry.torokhov, linux-input, linux-kernel; +Cc: Marcos Paulo de Souza

Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
---
 Documentation/kernel-parameters.txt | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a4f4d69..5ee70bd 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1457,7 +1457,12 @@ 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 and cleanup, only
+			     on cleanup, or never reset
+			Format: { 1 | Y | y | 0 | N | n }
+			1, Y, y: init and cleanup
+			0, N, n: don't reset controller
+			Default: only on cleanup
 	i8042.unlock	[HW] Unlock (ignore) the keylock
 	i8042.kbdreset  [HW] Reset device connected to KBD port
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Avoid selftests on some Asus models
  2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
  2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
  2016-09-25 13:25 ` [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation Marcos Paulo de Souza
@ 2016-10-01 10:56 ` Marcos Paulo de Souza
  2016-10-03  5:16   ` Dmitry Torokhov
  2 siblings, 1 reply; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-10-01 10:56 UTC (permalink / raw)
  To: dmitry.torokhov, linux-input, linux-kernel

ping?

On Sun, Sep 25, 2016 at 10:25:42AM -0300, Marcos Paulo de Souza wrote:
> Hi guys,
> 
> this is my forth iteration in this patch. I hope now this address all problems
> and, at least, most Asus models affect by this problem.
> 
> All models affected by this problem:
> A455LD
> K401LB
> K501LB
> K501LX
> R409L
> V502LX
> X302LA
> X450LCP
> X450LD
> X455LAB
> X455LDB
> X455LF
> Z450LA
> 
> Changes since v3:
> Add back all Asus models, instead of the dump decision of avoiding selftests in 
> all Asus laptops
> 
> Changes since v2:
> Avoid selftest in all Asus laptops
> 
> Changes since v1:
> Change kernel parameter i8042.reset to accept different values, instead of creating
> a new kernel parameter.
> 
> Please let me know if there is something that needs more polishment.
> 
> Thanks!
> 
> Marcos Paulo de Souza (2):
>   input/serio/i8042.c: Skipt selftest on ASUS laptops
>   kernel-parameters: Update i8042.reset parameter documentation
> 
>  Documentation/kernel-parameters.txt   |  7 ++-
>  drivers/input/serio/i8042-x86ia64io.h | 94 ++++++++++++++++++++++++++++++++++-
>  drivers/input/serio/i8042.c           | 38 +++++++++++---
>  3 files changed, 130 insertions(+), 9 deletions(-)
> 
> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Avoid selftests on some Asus models
  2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
@ 2016-10-03  5:16   ` Dmitry Torokhov
  2016-10-03 12:07     ` Marcos Paulo de Souza
  0 siblings, 1 reply; 6+ messages in thread
From: Dmitry Torokhov @ 2016-10-03  5:16 UTC (permalink / raw)
  To: Marcos Paulo de Souza; +Cc: linux-input, linux-kernel

On Sat, Oct 01, 2016 at 07:56:37AM -0300, Marcos Paulo de Souza wrote:
> ping?

Sorry for the delay, I was trying to wrap my mind around the new
always/never/sometimes logic.

Does the version below still work for you?

Thanks.

-- 
Dmitry

Input: i8042 - skip selftest on ASUS laptops

From: Marcos Paulo de Souza <marcos.souza.org@gmail.com>

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@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 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 a4f4d69..46726d4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1457,7 +1457,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 60d74e1..07d547d 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -518,6 +518,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 */
@@ -1080,12 +1164,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 405252a..89abfdb 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)
@@ -1482,7 +1515,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;

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Avoid selftests on some Asus models
  2016-10-03  5:16   ` Dmitry Torokhov
@ 2016-10-03 12:07     ` Marcos Paulo de Souza
  0 siblings, 0 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-10-03 12:07 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input, linux-kernel

Hi Dmitry,

On Sun, Oct 02, 2016 at 10:16:31PM -0700, Dmitry Torokhov wrote:
> On Sat, Oct 01, 2016 at 07:56:37AM -0300, Marcos Paulo de Souza wrote:
> > ping?
> 
> Sorry for the delay, I was trying to wrap my mind around the new
> always/never/sometimes logic.

No problem.

> 
> Does the version below still work for you?

Yes, still works for me.

Tested-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>

> 
> Thanks.
> 
> -- 
> Dmitry
> 
> Input: i8042 - skip selftest on ASUS laptops
> 
> From: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
> 
> 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@gmail.com>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
>  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 a4f4d69..46726d4 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1457,7 +1457,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 60d74e1..07d547d 100644
> --- a/drivers/input/serio/i8042-x86ia64io.h
> +++ b/drivers/input/serio/i8042-x86ia64io.h
> @@ -518,6 +518,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 */
> @@ -1080,12 +1164,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 405252a..89abfdb 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)
> @@ -1482,7 +1515,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;

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-10-03 12:07 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation Marcos Paulo de Souza
2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2016-10-03  5:16   ` Dmitry Torokhov
2016-10-03 12:07     ` Marcos Paulo de Souza

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).