diff mbox series

Input: i8042: Disable wake from keyboard by default on several AMD systems

Message ID 20230116184830.30573-1-mario.limonciello@amd.com
State New
Headers show
Series Input: i8042: Disable wake from keyboard by default on several AMD systems | expand

Commit Message

Mario Limonciello Jan. 16, 2023, 6:48 p.m. UTC
By default when the system is configured for suspend to idle by default
the keyboard is set up as a wake source.  This matches the behavior that
Windows uses for Modern Standby as well.

It has been reported that a variety of AMD based designs there are
spurious wakeups are happening where two IRQ sources are active.

```
PM: Triggering wakeup from IRQ 9
PM: Triggering wakeup from IRQ 1
```

In these designs IRQ 9 is the ACPI SCI and IRQ 1 is the PS/2 keyboard.
An example way to trigger this is to suspend the system and then unplug
the AC adapter.  The SOC will be in a hardware sleep state and plugging
in the AC adapter returns control to the kernel's s2idle loop.

Normally if just IRQ 9 was active the s2idle loop would advance any EC
transactions and no other IRQ being active would cause the s2idle loop
to put the SOC back into hardware sleep state.

When this bug occurred IRQ 1 is also active even if no keyboard activity
occurred. This causes the s2idle loop to break and the system to wake.

This is a platform firmware bug triggering IRQ1 without keyboard activity.
This occurs in Windows as well, but Windows will enter "SW DRIPS" and
then with no activity enters back into "HW DRIPS" (hardware sleep state).

This issue affects Renoir, Lucienne, Cezanne, and Barcelo based platforms
that use LPC EC. It does not happen on newer systems such as Mendocino or
Rembrandt.

It's been fixed in newer platform firmware, but determining whether the
system vendor uses an LPC EC and has deployed the fix is not possible.

To avoid triggering the bug check the CPU model and adjust the policy for
s2idle wakeup from keyboard on these systems to be disabled by default.

Users who know that their firmware is fixed and want to use wakeup from
keyboard can manually enable wakeup from sysfs by modifying
`/sys/bus/serio/devices/serio0/power/wakeup`.

Reported-by: Xaver Hugl <xaver.hugl@gmail.com>
Tested-by: Xaver Hugl <xaver.hugl@gmail.com>
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2115#note_1724008
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 drivers/input/serio/i8042.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

Comments

Dmitry Torokhov Jan. 16, 2023, 10:59 p.m. UTC | #1
Hi Mario,

On Mon, Jan 16, 2023 at 12:48:30PM -0600, Mario Limonciello wrote:
> By default when the system is configured for suspend to idle by default
> the keyboard is set up as a wake source.  This matches the behavior that
> Windows uses for Modern Standby as well.
> 
> It has been reported that a variety of AMD based designs there are
> spurious wakeups are happening where two IRQ sources are active.
> 
> ```
> PM: Triggering wakeup from IRQ 9
> PM: Triggering wakeup from IRQ 1
> ```
> 
> In these designs IRQ 9 is the ACPI SCI and IRQ 1 is the PS/2 keyboard.
> An example way to trigger this is to suspend the system and then unplug
> the AC adapter.  The SOC will be in a hardware sleep state and plugging
> in the AC adapter returns control to the kernel's s2idle loop.
> 
> Normally if just IRQ 9 was active the s2idle loop would advance any EC
> transactions and no other IRQ being active would cause the s2idle loop
> to put the SOC back into hardware sleep state.
> 
> When this bug occurred IRQ 1 is also active even if no keyboard activity
> occurred. This causes the s2idle loop to break and the system to wake.
> 
> This is a platform firmware bug triggering IRQ1 without keyboard activity.
> This occurs in Windows as well, but Windows will enter "SW DRIPS" and
> then with no activity enters back into "HW DRIPS" (hardware sleep state).
> 
> This issue affects Renoir, Lucienne, Cezanne, and Barcelo based platforms
> that use LPC EC. It does not happen on newer systems such as Mendocino or
> Rembrandt.
> 
> It's been fixed in newer platform firmware, but determining whether the
> system vendor uses an LPC EC and has deployed the fix is not possible.
> 
> To avoid triggering the bug check the CPU model and adjust the policy for
> s2idle wakeup from keyboard on these systems to be disabled by default.

I think there are Chrome devices using these chipsets that use coreboot
firmware and do not exhibit the problematic behavior, so in addition to
CPU model check we need to check the firmware origin as well.

> 
> Users who know that their firmware is fixed and want to use wakeup from
> keyboard can manually enable wakeup from sysfs by modifying
> `/sys/bus/serio/devices/serio0/power/wakeup`.
> 
> Reported-by: Xaver Hugl <xaver.hugl@gmail.com>
> Tested-by: Xaver Hugl <xaver.hugl@gmail.com>
> Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2115#note_1724008
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
>  drivers/input/serio/i8042.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
> index 6dac7c1853a54..c9eeca18c0816 100644
> --- a/drivers/input/serio/i8042.c
> +++ b/drivers/input/serio/i8042.c
> @@ -23,6 +23,7 @@
>  #include <linux/suspend.h>
>  #include <linux/property.h>
>  
> +#include <asm/cpu_device_id.h>

Is it available on all architectures? Historically we were trying to
hide platform details in drivers/input/serio/i8042-acpipnpio.h

>  #include <asm/io.h>
>  
>  MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
> @@ -433,6 +434,26 @@ static void i8042_port_close(struct serio *serio)
>  	i8042_interrupt(0, NULL);
>  }
>  
> +static bool i8042_should_wakeup_by_default(struct serio *serio)
> +{
> +#ifdef CONFIG_X86
> +	const struct x86_cpu_id irq1_bug_cpu_ids[] = {
> +		X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 96, NULL),	/* Renoir */
> +		X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 104, NULL),	/* Lucienne */
> +		X86_MATCH_VENDOR_FAM_MODEL(AMD, 25, 80, NULL),	/* Cezanne/Barcelo */
> +		{}
> +	};
> +
> +	if (x86_match_cpu(irq1_bug_cpu_ids)) {
> +		pr_info_once("Disabling wakeup from keyboard to avoid firmware bug\n");
> +		return false;
> +	}
> +#endif
> +	if (!pm_suspend_default_s2idle())
> +		return false;
> +	return serio == i8042_ports[I8042_KBD_PORT_NO].serio;
> +}
> +
>  /*
>   * i8042_start() is called by serio core when port is about to finish
>   * registering. It will mark port as existing so i8042_interrupt can
> @@ -451,10 +472,8 @@ static int i8042_start(struct serio *serio)
>  	 * behavior on many platforms using suspend-to-RAM (ACPI S3)
>  	 * by default.
>  	 */
> -	if (pm_suspend_default_s2idle() &&
> -	    serio == i8042_ports[I8042_KBD_PORT_NO].serio) {
> +	if (i8042_should_wakeup_by_default(serio))
>  		device_set_wakeup_enable(&serio->dev, true);
> -	}
>  
>  	spin_lock_irq(&i8042_lock);
>  	port->exists = true;
> -- 
> 2.34.1
> 

Thanks.
Mario Limonciello Jan. 17, 2023, 2:51 a.m. UTC | #2
[Public]



> -----Original Message-----
> From: Limonciello, Mario <Mario.Limonciello@amd.com>
> Sent: Monday, January 16, 2023 12:49
> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>; linux-
> kernel@vger.kernel.org
> Cc: Limonciello, Mario <Mario.Limonciello@amd.com>; Xaver Hugl
> <xaver.hugl@gmail.com>; linux-input@vger.kernel.org
> Subject: [PATCH] Input: i8042: Disable wake from keyboard by default on several
> AMD systems
> 
> By default when the system is configured for suspend to idle by default
> the keyboard is set up as a wake source.  This matches the behavior that
> Windows uses for Modern Standby as well.
> 
> It has been reported that a variety of AMD based designs there are
> spurious wakeups are happening where two IRQ sources are active.
> 
> ```
> PM: Triggering wakeup from IRQ 9
> PM: Triggering wakeup from IRQ 1
> ```
> 
> In these designs IRQ 9 is the ACPI SCI and IRQ 1 is the PS/2 keyboard.
> An example way to trigger this is to suspend the system and then unplug
> the AC adapter.  The SOC will be in a hardware sleep state and plugging
> in the AC adapter returns control to the kernel's s2idle loop.
> 
> Normally if just IRQ 9 was active the s2idle loop would advance any EC
> transactions and no other IRQ being active would cause the s2idle loop
> to put the SOC back into hardware sleep state.
> 
> When this bug occurred IRQ 1 is also active even if no keyboard activity
> occurred. This causes the s2idle loop to break and the system to wake.
> 
> This is a platform firmware bug triggering IRQ1 without keyboard activity.
> This occurs in Windows as well, but Windows will enter "SW DRIPS" and
> then with no activity enters back into "HW DRIPS" (hardware sleep state).
> 
> This issue affects Renoir, Lucienne, Cezanne, and Barcelo based platforms
> that use LPC EC. It does not happen on newer systems such as Mendocino or
> Rembrandt.
> 
> It's been fixed in newer platform firmware, but determining whether the
> system vendor uses an LPC EC and has deployed the fix is not possible.
> 
> To avoid triggering the bug check the CPU model and adjust the policy for
> s2idle wakeup from keyboard on these systems to be disabled by default.
> 
> Users who know that their firmware is fixed and want to use wakeup from
> keyboard can manually enable wakeup from sysfs by modifying
> `/sys/bus/serio/devices/serio0/power/wakeup`.
> 
> Reported-by: Xaver Hugl <xaver.hugl@gmail.com>
> Tested-by: Xaver Hugl <xaver.hugl@gmail.com>
> Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2115#note_1724008
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---

Hi,

Please disregard this patch.  In thinking about it more, I don't want to put the
workaround directly in i8042.  I am working with Xaver to test deploying the
workaround in platform/x86/amd/pmc.c instead so that we can ensure it only
runs on the firmware versions known to have the flaw and will post a new
patch when we have it working.

Thanks,
diff mbox series

Patch

diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 6dac7c1853a54..c9eeca18c0816 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -23,6 +23,7 @@ 
 #include <linux/suspend.h>
 #include <linux/property.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -433,6 +434,26 @@  static void i8042_port_close(struct serio *serio)
 	i8042_interrupt(0, NULL);
 }
 
+static bool i8042_should_wakeup_by_default(struct serio *serio)
+{
+#ifdef CONFIG_X86
+	const struct x86_cpu_id irq1_bug_cpu_ids[] = {
+		X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 96, NULL),	/* Renoir */
+		X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 104, NULL),	/* Lucienne */
+		X86_MATCH_VENDOR_FAM_MODEL(AMD, 25, 80, NULL),	/* Cezanne/Barcelo */
+		{}
+	};
+
+	if (x86_match_cpu(irq1_bug_cpu_ids)) {
+		pr_info_once("Disabling wakeup from keyboard to avoid firmware bug\n");
+		return false;
+	}
+#endif
+	if (!pm_suspend_default_s2idle())
+		return false;
+	return serio == i8042_ports[I8042_KBD_PORT_NO].serio;
+}
+
 /*
  * i8042_start() is called by serio core when port is about to finish
  * registering. It will mark port as existing so i8042_interrupt can
@@ -451,10 +472,8 @@  static int i8042_start(struct serio *serio)
 	 * behavior on many platforms using suspend-to-RAM (ACPI S3)
 	 * by default.
 	 */
-	if (pm_suspend_default_s2idle() &&
-	    serio == i8042_ports[I8042_KBD_PORT_NO].serio) {
+	if (i8042_should_wakeup_by_default(serio))
 		device_set_wakeup_enable(&serio->dev, true);
-	}
 
 	spin_lock_irq(&i8042_lock);
 	port->exists = true;