mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	ACPI: EC / PM: Disable non-wakeup GPEs for suspend-to-idle
There are systems in which non-wakeup GPEs fire during the "noirq"
suspend stage of suspending devices and that effectively prevents the
system that tries to suspend to idle from entering any low-power
state at all.  If the offending GPE fires regularly and often enough,
the system appears to be suspended, but in fact it is in a tight loop
over "noirq" suspend and "noirq" resume of devices all the time.
To prevent that from happening, disable all non-wakeup GPEs except
for the EC GPE for suspend-to-idle (the EC GPE is special, because
on some systems it has to be enabled for power button wakeup events
to be generated as expected).
Fixes: 147a7d9d25 (ACPI / PM: Do not reconfigure GPEs for suspend-to-idle)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=201987
Reported-by: Zhang Rui <rui.zhang@intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
			
			
This commit is contained in:
		
							parent
							
								
									7566ec393f
								
							
						
					
					
						commit
						f941d3e41d
					
				
					 3 changed files with 25 additions and 0 deletions
				
			
		| 
						 | 
					@ -1034,6 +1034,18 @@ void acpi_ec_unblock_transactions(void)
 | 
				
			||||||
		acpi_ec_start(first_ec, true);
 | 
							acpi_ec_start(first_ec, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void acpi_ec_mark_gpe_for_wake(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (first_ec && !ec_no_wakeup)
 | 
				
			||||||
 | 
							acpi_mark_gpe_for_wake(NULL, first_ec->gpe);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void acpi_ec_set_gpe_wake_mask(u8 action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (first_ec && !ec_no_wakeup)
 | 
				
			||||||
 | 
							acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void acpi_ec_dispatch_gpe(void)
 | 
					void acpi_ec_dispatch_gpe(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (first_ec)
 | 
						if (first_ec)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,6 +188,8 @@ int acpi_ec_ecdt_probe(void);
 | 
				
			||||||
int acpi_ec_dsdt_probe(void);
 | 
					int acpi_ec_dsdt_probe(void);
 | 
				
			||||||
void acpi_ec_block_transactions(void);
 | 
					void acpi_ec_block_transactions(void);
 | 
				
			||||||
void acpi_ec_unblock_transactions(void);
 | 
					void acpi_ec_unblock_transactions(void);
 | 
				
			||||||
 | 
					void acpi_ec_mark_gpe_for_wake(void);
 | 
				
			||||||
 | 
					void acpi_ec_set_gpe_wake_mask(u8 action);
 | 
				
			||||||
void acpi_ec_dispatch_gpe(void);
 | 
					void acpi_ec_dispatch_gpe(void);
 | 
				
			||||||
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 | 
					int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
 | 
				
			||||||
			      acpi_handle handle, acpi_ec_query_func func,
 | 
								      acpi_handle handle, acpi_ec_query_func func,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -940,6 +940,8 @@ static int lps0_device_attach(struct acpi_device *adev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
 | 
							acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
 | 
				
			||||||
				  bitmask);
 | 
									  bitmask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							acpi_ec_mark_gpe_for_wake();
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		acpi_handle_debug(adev->handle,
 | 
							acpi_handle_debug(adev->handle,
 | 
				
			||||||
				  "_DSM function 0 evaluation failed\n");
 | 
									  "_DSM function 0 evaluation failed\n");
 | 
				
			||||||
| 
						 | 
					@ -968,11 +970,16 @@ static int acpi_s2idle_prepare(void)
 | 
				
			||||||
	if (lps0_device_handle) {
 | 
						if (lps0_device_handle) {
 | 
				
			||||||
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
 | 
							acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
 | 
				
			||||||
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
 | 
							acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (acpi_sci_irq_valid())
 | 
						if (acpi_sci_irq_valid())
 | 
				
			||||||
		enable_irq_wake(acpi_sci_irq);
 | 
							enable_irq_wake(acpi_sci_irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Change the configuration of GPEs to avoid spurious wakeup. */
 | 
				
			||||||
 | 
						acpi_enable_all_wakeup_gpes();
 | 
				
			||||||
 | 
						acpi_os_wait_events_complete();
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1017,10 +1024,14 @@ static void acpi_s2idle_sync(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void acpi_s2idle_restore(void)
 | 
					static void acpi_s2idle_restore(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						acpi_enable_all_runtime_gpes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (acpi_sci_irq_valid())
 | 
						if (acpi_sci_irq_valid())
 | 
				
			||||||
		disable_irq_wake(acpi_sci_irq);
 | 
							disable_irq_wake(acpi_sci_irq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (lps0_device_handle) {
 | 
						if (lps0_device_handle) {
 | 
				
			||||||
 | 
							acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
 | 
							acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
 | 
				
			||||||
		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
 | 
							acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue