Commit 883fd0ab authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+1 −22
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <linux/dmi.h>
#include <linux/ioport.h>
#include <asm/e820/api.h>

@@ -24,31 +23,11 @@ static void resource_clip(struct resource *res, resource_size_t start,
		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)
{
	int i, year = dmi_get_bios_year();
	int i;
	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++) {
		entry = &e820_table->entries[i];

+10 −0
Original line number Diff line number Diff line
@@ -2065,6 +2065,16 @@ bool acpi_ec_dispatch_gpe(void)
	if (acpi_any_gpe_status_set(first_ec->gpe))
		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
	 * to allow the caller to process events properly after that.
+5 −10
Original line number Diff line number Diff line
@@ -736,21 +736,15 @@ bool acpi_s2idle_wake(void)
			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()) {
			pm_pr_dbg("ACPI non-EC GPE wakeup\n");
			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();

		/*
@@ -764,6 +758,7 @@ bool acpi_s2idle_wake(void)
			return true;
		}

		pm_wakeup_clear(acpi_sci_irq);
		rearm_wake_irq(acpi_sci_irq);
	}

+4 −8
Original line number Diff line number Diff line
@@ -424,14 +424,10 @@ static int lps0_device_attach(struct acpi_device *adev,
		mem_sleep_current = PM_SUSPEND_TO_IDLE;

	/*
	 * Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't
	 * use intel-hid or intel-vbtn but require the EC GPE to be enabled while
	 * suspended for certain wakeup devices to work, so mark it as wakeup-capable.
	 *
	 * Only enable on !AMD as enabling this universally causes problems for a number
	 * of AMD based systems.
	 * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
	 * EC GPE to be enabled while suspended for certain wakeup devices to
	 * work, so mark it as wakeup-capable.
	 */
	if (!acpi_s2idle_vendor_amd())
	acpi_ec_mark_gpe_for_wake();

	return 0;
+34 −7
Original line number Diff line number Diff line
@@ -34,7 +34,8 @@ suspend_state_t pm_suspend_target_state;
bool events_check_enabled __read_mostly;

/* 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. */
static atomic_t pm_abort_suspend __read_mostly;
@@ -942,19 +943,45 @@ void pm_system_cancel_wakeup(void)
	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;
	if (reset)
	raw_spin_lock_irq(&wakeup_irq_lock);

	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);
}

void pm_system_irq_wakeup(unsigned int irq_number)
{
	if (pm_wakeup_irq == 0) {
		pm_wakeup_irq = irq_number;
	unsigned long flags;

	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();
}

unsigned int pm_wakeup_irq(void)
{
	return wakeup_irq[0];
}

/**
Loading