mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ACPI: sleep: Avoid breaking S3 wakeup due to might_sleep()
The addition of might_sleep() to down_timeout() caused the latter to
enable interrupts unconditionally in some cases, which in turn broke
the ACPI S3 wakeup path in acpi_suspend_enter(), where down_timeout()
is called by acpi_disable_all_gpes() via acpi_ut_acquire_mutex().
Namely, if CONFIG_DEBUG_ATOMIC_SLEEP is set, might_sleep() causes
might_resched() to be used and if CONFIG_PREEMPT_VOLUNTARY is set,
this triggers __cond_resched() which may call preempt_schedule_common(),
so __schedule() gets invoked and it ends up with enabled interrupts (in
the prev == next case).
Now, enabling interrupts early in the S3 wakeup path causes the kernel
to crash.
Address this by modifying acpi_suspend_enter() to disable GPEs without
attempting to acquire the sleeping lock which is not needed in that code
path anyway.
Fixes: 99409b935c ("locking/semaphore: Add might_sleep() to down_*() family")
Reported-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: 5.15+ <stable@vger.kernel.org> # 5.15+
			
			
This commit is contained in:
		
							parent
							
								
									858fd168a9
								
							
						
					
					
						commit
						22db06337f
					
				
					 3 changed files with 13 additions and 6 deletions
				
			
		| 
						 | 
					@ -101,8 +101,6 @@ acpi_status
 | 
				
			||||||
acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
 | 
					acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
 | 
				
			||||||
		       acpi_event_status *event_status);
 | 
							       acpi_event_status *event_status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
acpi_status acpi_hw_disable_all_gpes(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
acpi_status acpi_hw_enable_all_runtime_gpes(void);
 | 
					acpi_status acpi_hw_enable_all_runtime_gpes(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
acpi_status acpi_hw_enable_all_wakeup_gpes(void);
 | 
					acpi_status acpi_hw_enable_all_wakeup_gpes(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -636,11 +636,19 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Disable and clear GPE status before interrupt is enabled. Some GPEs
 | 
						 * Disable all GPE and clear their status bits before interrupts are
 | 
				
			||||||
	 * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
 | 
						 * enabled. Some GPEs (like wakeup GPEs) have no handlers and this can
 | 
				
			||||||
	 * acpi_leave_sleep_state will reenable specific GPEs later
 | 
						 * prevent them from producing spurious interrups.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * acpi_leave_sleep_state() will reenable specific GPEs later.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Because this code runs on one CPU with disabled interrupts (all of
 | 
				
			||||||
 | 
						 * the other CPUs are offline at this time), it need not acquire any
 | 
				
			||||||
 | 
						 * sleeping locks which may trigger an implicit preemption point even
 | 
				
			||||||
 | 
						 * if there is no contention, so avoid doing that by using a low-level
 | 
				
			||||||
 | 
						 * library routine here.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	acpi_disable_all_gpes();
 | 
						acpi_hw_disable_all_gpes();
 | 
				
			||||||
	/* Allow EC transactions to happen. */
 | 
						/* Allow EC transactions to happen. */
 | 
				
			||||||
	acpi_ec_unblock_transactions();
 | 
						acpi_ec_unblock_transactions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -761,6 +761,7 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
 | 
				
			||||||
						     acpi_event_status
 | 
											     acpi_event_status
 | 
				
			||||||
						     *event_status))
 | 
											     *event_status))
 | 
				
			||||||
ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number))
 | 
					ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number))
 | 
				
			||||||
 | 
					ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_hw_disable_all_gpes(void))
 | 
				
			||||||
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
 | 
					ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
 | 
				
			||||||
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
 | 
					ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
 | 
				
			||||||
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
 | 
					ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue