Commit 883fd0ab authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'acpi-5.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI fixes from Rafael Wysocki:
 "These revert two commits that turned out to be problematic and fix two
  issues related to wakeup from suspend-to-idle on x86.

  Specifics:

   - Revert a recent change that attempted to avoid issues with
     conflicting address ranges during PCI initialization, because it
     turned out to introduce a regression (Hans de Goede).

   - Revert a change that limited EC GPE wakeups from suspend-to-idle to
     systems based on Intel hardware, because it turned out that systems
     based on hardware from other vendors depended on that functionality
     too (Mario Limonciello).

   - Fix two issues related to the handling of wakeup interrupts and
     wakeup events signaled through the EC GPE during suspend-to-idle on
     x86 (Rafael Wysocki)"

* tag 'acpi-5.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  x86/PCI: revert "Ignore E820 reservations for bridge windows on newer systems"
  PM: s2idle: ACPI: Fix wakeup interrupts handling
  ACPI: PM: s2idle: Cancel wakeup before dispatching EC GPE
  ACPI: PM: Revert "Only mark EC GPE for wakeup on Intel systems"
parents 8ce964b5 27a98fe6
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/dmi.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <asm/e820/api.h> #include <asm/e820/api.h>
...@@ -24,31 +23,11 @@ static void resource_clip(struct resource *res, resource_size_t start, ...@@ -24,31 +23,11 @@ static void resource_clip(struct resource *res, resource_size_t start,
res->start = end + 1; res->start = end + 1;
} }
/*
* Some BIOS-es contain a bug where they add addresses which map to
* system RAM in the PCI host bridge window returned by the ACPI _CRS
* method, see commit 4dc2287c1805 ("x86: avoid E820 regions when
* allocating address space"). To avoid this Linux by default excludes
* E820 reservations when allocating addresses since 2010.
* In 2019 some systems have shown-up with E820 reservations which cover
* the entire _CRS returned PCI host bridge window, causing all attempts
* to assign memory to PCI BARs to fail if Linux uses E820 reservations.
*
* Ideally Linux would fully stop using E820 reservations, but then
* the old systems this was added for will regress.
* Instead keep the old behavior for old systems, while ignoring the
* E820 reservations for any systems from now on.
*/
static void remove_e820_regions(struct resource *avail) static void remove_e820_regions(struct resource *avail)
{ {
int i, year = dmi_get_bios_year(); int i;
struct e820_entry *entry; struct e820_entry *entry;
if (year >= 2018)
return;
pr_info_once("PCI: Removing E820 reservations from host bridge windows\n");
for (i = 0; i < e820_table->nr_entries; i++) { for (i = 0; i < e820_table->nr_entries; i++) {
entry = &e820_table->entries[i]; entry = &e820_table->entries[i];
......
...@@ -2065,6 +2065,16 @@ bool acpi_ec_dispatch_gpe(void) ...@@ -2065,6 +2065,16 @@ bool acpi_ec_dispatch_gpe(void)
if (acpi_any_gpe_status_set(first_ec->gpe)) if (acpi_any_gpe_status_set(first_ec->gpe))
return true; return true;
/*
* Cancel the SCI wakeup and process all pending events in case there
* are any wakeup ones in there.
*
* Note that if any non-EC GPEs are active at this point, the SCI will
* retrigger after the rearming in acpi_s2idle_wake(), so no events
* should be missed by canceling the wakeup here.
*/
pm_system_cancel_wakeup();
/* /*
* Dispatch the EC GPE in-band, but do not report wakeup in any case * Dispatch the EC GPE in-band, but do not report wakeup in any case
* to allow the caller to process events properly after that. * to allow the caller to process events properly after that.
......
...@@ -736,21 +736,15 @@ bool acpi_s2idle_wake(void) ...@@ -736,21 +736,15 @@ bool acpi_s2idle_wake(void)
return true; return true;
} }
/* Check non-EC GPE wakeups and dispatch the EC GPE. */ /*
* Check non-EC GPE wakeups and if there are none, cancel the
* SCI-related wakeup and dispatch the EC GPE.
*/
if (acpi_ec_dispatch_gpe()) { if (acpi_ec_dispatch_gpe()) {
pm_pr_dbg("ACPI non-EC GPE wakeup\n"); pm_pr_dbg("ACPI non-EC GPE wakeup\n");
return true; return true;
} }
/*
* Cancel the SCI wakeup and process all pending events in case
* there are any wakeup ones in there.
*
* Note that if any non-EC GPEs are active at this point, the
* SCI will retrigger after the rearming below, so no events
* should be missed by canceling the wakeup here.
*/
pm_system_cancel_wakeup();
acpi_os_wait_events_complete(); acpi_os_wait_events_complete();
/* /*
...@@ -764,6 +758,7 @@ bool acpi_s2idle_wake(void) ...@@ -764,6 +758,7 @@ bool acpi_s2idle_wake(void)
return true; return true;
} }
pm_wakeup_clear(acpi_sci_irq);
rearm_wake_irq(acpi_sci_irq); rearm_wake_irq(acpi_sci_irq);
} }
......
...@@ -424,14 +424,10 @@ static int lps0_device_attach(struct acpi_device *adev, ...@@ -424,14 +424,10 @@ static int lps0_device_attach(struct acpi_device *adev,
mem_sleep_current = PM_SUSPEND_TO_IDLE; mem_sleep_current = PM_SUSPEND_TO_IDLE;
/* /*
* Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
* use intel-hid or intel-vbtn but require the EC GPE to be enabled while * EC GPE to be enabled while suspended for certain wakeup devices to
* suspended for certain wakeup devices to work, so mark it as wakeup-capable. * work, so mark it as wakeup-capable.
*
* Only enable on !AMD as enabling this universally causes problems for a number
* of AMD based systems.
*/ */
if (!acpi_s2idle_vendor_amd())
acpi_ec_mark_gpe_for_wake(); acpi_ec_mark_gpe_for_wake();
return 0; return 0;
......
...@@ -34,7 +34,8 @@ suspend_state_t pm_suspend_target_state; ...@@ -34,7 +34,8 @@ suspend_state_t pm_suspend_target_state;
bool events_check_enabled __read_mostly; bool events_check_enabled __read_mostly;
/* First wakeup IRQ seen by the kernel in the last cycle. */ /* First wakeup IRQ seen by the kernel in the last cycle. */
unsigned int pm_wakeup_irq __read_mostly; static unsigned int wakeup_irq[2] __read_mostly;
static DEFINE_RAW_SPINLOCK(wakeup_irq_lock);
/* If greater than 0 and the system is suspending, terminate the suspend. */ /* If greater than 0 and the system is suspending, terminate the suspend. */
static atomic_t pm_abort_suspend __read_mostly; static atomic_t pm_abort_suspend __read_mostly;
...@@ -942,19 +943,45 @@ void pm_system_cancel_wakeup(void) ...@@ -942,19 +943,45 @@ void pm_system_cancel_wakeup(void)
atomic_dec_if_positive(&pm_abort_suspend); atomic_dec_if_positive(&pm_abort_suspend);
} }
void pm_wakeup_clear(bool reset) void pm_wakeup_clear(unsigned int irq_number)
{ {
pm_wakeup_irq = 0; raw_spin_lock_irq(&wakeup_irq_lock);
if (reset)
if (irq_number && wakeup_irq[0] == irq_number)
wakeup_irq[0] = wakeup_irq[1];
else
wakeup_irq[0] = 0;
wakeup_irq[1] = 0;
raw_spin_unlock_irq(&wakeup_irq_lock);
if (!irq_number)
atomic_set(&pm_abort_suspend, 0); atomic_set(&pm_abort_suspend, 0);
} }
void pm_system_irq_wakeup(unsigned int irq_number) void pm_system_irq_wakeup(unsigned int irq_number)
{ {
if (pm_wakeup_irq == 0) { unsigned long flags;
pm_wakeup_irq = irq_number;
raw_spin_lock_irqsave(&wakeup_irq_lock, flags);
if (wakeup_irq[0] == 0)
wakeup_irq[0] = irq_number;
else if (wakeup_irq[1] == 0)
wakeup_irq[1] = irq_number;
else
irq_number = 0;
raw_spin_unlock_irqrestore(&wakeup_irq_lock, flags);
if (irq_number)
pm_system_wakeup(); pm_system_wakeup();
} }
unsigned int pm_wakeup_irq(void)
{
return wakeup_irq[0];
} }
/** /**
......
...@@ -497,14 +497,14 @@ extern void ksys_sync_helper(void); ...@@ -497,14 +497,14 @@ extern void ksys_sync_helper(void);
/* drivers/base/power/wakeup.c */ /* drivers/base/power/wakeup.c */
extern bool events_check_enabled; extern bool events_check_enabled;
extern unsigned int pm_wakeup_irq;
extern suspend_state_t pm_suspend_target_state; extern suspend_state_t pm_suspend_target_state;
extern bool pm_wakeup_pending(void); extern bool pm_wakeup_pending(void);
extern void pm_system_wakeup(void); extern void pm_system_wakeup(void);
extern void pm_system_cancel_wakeup(void); extern void pm_system_cancel_wakeup(void);
extern void pm_wakeup_clear(bool reset); extern void pm_wakeup_clear(unsigned int irq_number);
extern void pm_system_irq_wakeup(unsigned int irq_number); extern void pm_system_irq_wakeup(unsigned int irq_number);
extern unsigned int pm_wakeup_irq(void);
extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count); extern bool pm_save_wakeup_count(unsigned int count);
extern void pm_wakep_autosleep_enabled(bool set); extern void pm_wakep_autosleep_enabled(bool set);
......
...@@ -504,7 +504,10 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj, ...@@ -504,7 +504,10 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
struct kobj_attribute *attr, struct kobj_attribute *attr,
char *buf) char *buf)
{ {
return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA; if (!pm_wakeup_irq())
return -ENODATA;
return sprintf(buf, "%u\n", pm_wakeup_irq());
} }
power_attr_ro(pm_wakeup_irq); power_attr_ro(pm_wakeup_irq);
......
...@@ -134,7 +134,7 @@ int freeze_processes(void) ...@@ -134,7 +134,7 @@ int freeze_processes(void)
if (!pm_freezing) if (!pm_freezing)
atomic_inc(&system_freezing_cnt); atomic_inc(&system_freezing_cnt);
pm_wakeup_clear(true); pm_wakeup_clear(0);
pr_info("Freezing user space processes ... "); pr_info("Freezing user space processes ... ");
pm_freezing = true; pm_freezing = true;
error = try_to_freeze_tasks(true); error = try_to_freeze_tasks(true);
......
...@@ -136,8 +136,6 @@ static void s2idle_loop(void) ...@@ -136,8 +136,6 @@ static void s2idle_loop(void)
break; break;
} }
pm_wakeup_clear(false);
s2idle_enter(); s2idle_enter();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment