Received: by 2002:a25:1506:0:0:0:0:0 with SMTP id 6csp3691669ybv; Mon, 10 Feb 2020 04:48:06 -0800 (PST) X-Google-Smtp-Source: APXvYqwm+DQbekDUICOfsnx3dfLIgKTgswU1roevsiMgq+JXlNpBBXF7Q6RCl3ut4YPU+ffQldvL X-Received: by 2002:a05:6830:210d:: with SMTP id i13mr941637otc.192.1581338886057; Mon, 10 Feb 2020 04:48:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1581338886; cv=none; d=google.com; s=arc-20160816; b=gC2C+wXWVfSuUaemH9wGZ0ZQGi80tocu43SHmTJJW4DYYF2ZqTsdurUL1B3fw3paGB vMalARisoi9Zsmk1HBMUCc2VE3Jp+iDKZjFpqTJPipe+jqs81q5w040xzCrWQUAefLrx vZnoOpkY2GG/vjxzLD3nqzl8e3vpg6twiSEupjPyhnwmStwBsSYhl5+Hjtm3oziex5HU CThjpZX5WEsC+OHoSfShpH/c+hkINamUE8kHkCbHh58PGKLuCD+bfbHmrltZuJgi/Llf k2SBNgrbxyKlFhjoH4uGCwJoRtAjhuLuiGNI4Q2B2lZBWEtXZdgDntN9ssVK94R5DRPS CXIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=6zBNZJB2XjG+/rhlJZb5+TtjAsoiT2SzX8bhU4wGXP4=; b=VCQ5z4GOaiwYpEheFRAjM/KbaZAfELEpJMxsFQsawDpUkNKxSDzSZjqG1Y5qSD0/dg lYA8XurJSRvqil+xOxHwt/746XWQdYSWlB2GZcHQThuyVWYixZ9VDagXwCa9IoUPCKID w0TpJN71V5TMLq7oxCTmw9YE8TaKkI6nbSNulTKIBZKUS016u6tNNf+cOTKbDghpT/5S qef2p+ayO0e54jeVzKf19CR6Hob8YYudOkLYNqdtHSik7+XphA371U/BQDG4wqDb8uB+ uIoWX9876Wws3Zk6gXhPIE3buzfsCu8OoLV20mcnAnyvoOXv0uSNNkj/42gmUDXv2z0g EQ/A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m8si124259oim.180.2020.02.10.04.47.54; Mon, 10 Feb 2020 04:48:06 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730923AbgBJMrv (ORCPT + 99 others); Mon, 10 Feb 2020 07:47:51 -0500 Received: from cloudserver094114.home.pl ([79.96.170.134]:56364 "EHLO cloudserver094114.home.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730491AbgBJMpc (ORCPT ); Mon, 10 Feb 2020 07:45:32 -0500 Received: from 79.184.254.199.ipv4.supernova.orange.pl (79.184.254.199) (HELO kreacher.localnet) by serwer1319399.home.pl (79.96.170.134) with SMTP (IdeaSmtpServer 0.83.341) id b5b46441409b89cc; Mon, 10 Feb 2020 13:45:29 +0100 From: "Rafael J. Wysocki" To: Linux ACPI Cc: Linux PM , LKML , Zhang Rui , David Box Subject: [PATCH] ACPI: PM: s2idle: Avoid possible race related to the EC GPE Date: Mon, 10 Feb 2020 13:45:29 +0100 Message-ID: <11464642.O9o76ZdvQC@kreacher> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Rafael J. Wysocki It is theoretically possible for the ACPI EC GPE to be set after the s2idle_ops->wake() called from s2idle_loop() has returned and before the subsequent pm_wakeup_pending() check is carried out. If that happens, the resulting wakeup event will cause the system to resume even though it may be a spurious one. To avoid that race, first make the ->wake() callback in struct platform_s2idle_ops return a bool value indicating whether or not to let the system resume and rearrange s2idle_loop() to use that value instad of the direct pm_wakeup_pending() call if ->wake() is present. Next, rework acpi_s2idle_wake() to process EC events and check pm_wakeup_pending() before rearming the SCI for system wakeup to prevent it from triggering prematurely and add comments to that function to explain the rationale for the new code flow. Fixes: 56b991849009 ("PM: sleep: Simplify suspend-to-idle control flow") Cc: 5.4+ # 5.4+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 46 ++++++++++++++++++++++++++++++++-------------- include/linux/suspend.h | 2 +- kernel/power/suspend.c | 9 +++++---- 3 files changed, 38 insertions(+), 19 deletions(-) Index: linux-pm/drivers/acpi/sleep.c =================================================================== --- linux-pm.orig/drivers/acpi/sleep.c +++ linux-pm/drivers/acpi/sleep.c @@ -990,21 +990,28 @@ static void acpi_s2idle_sync(void) acpi_os_wait_events_complete(); /* synchronize Notify handling */ } -static void acpi_s2idle_wake(void) +static bool acpi_s2idle_wake(void) { - /* - * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the SCI has - * not triggered while suspended, so bail out. - */ - if (!acpi_sci_irq_valid() || - irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) - return; - - /* - * If there are EC events to process, the wakeup may be a spurious one - * coming from the EC. - */ - if (acpi_ec_dispatch_gpe()) { + if (!acpi_sci_irq_valid()) + return pm_wakeup_pending(); + + while (pm_wakeup_pending()) { + /* + * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the + * SCI has not triggered while suspended, so bail out (the + * wakeup is pending anyway and the SCI is not the source of + * it). + */ + if (irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) + return true; + + /* + * If there are no EC events to process, the wakeup is regarded + * as a genuine one. + */ + if (!acpi_ec_dispatch_gpe()) + return true; + /* * Cancel the wakeup and process all pending events in case * there are any wakeup ones in there. @@ -1017,8 +1024,19 @@ static void acpi_s2idle_wake(void) acpi_s2idle_sync(); + /* + * The SCI is in the "suspended" state now and it cannot produce + * new wakeup events till the rearming below, so if any of them + * are pending here, they must be resulting from the processing + * of EC events above or coming from somewhere else. + */ + if (pm_wakeup_pending()) + return true; + rearm_wake_irq(acpi_sci_irq); } + + return false; } static void acpi_s2idle_restore_early(void) Index: linux-pm/include/linux/suspend.h =================================================================== --- linux-pm.orig/include/linux/suspend.h +++ linux-pm/include/linux/suspend.h @@ -191,7 +191,7 @@ struct platform_s2idle_ops { int (*begin)(void); int (*prepare)(void); int (*prepare_late)(void); - void (*wake)(void); + bool (*wake)(void); void (*restore_early)(void); void (*restore)(void); void (*end)(void); Index: linux-pm/kernel/power/suspend.c =================================================================== --- linux-pm.orig/kernel/power/suspend.c +++ linux-pm/kernel/power/suspend.c @@ -131,11 +131,12 @@ static void s2idle_loop(void) * to avoid them upfront. */ for (;;) { - if (s2idle_ops && s2idle_ops->wake) - s2idle_ops->wake(); - - if (pm_wakeup_pending()) + if (s2idle_ops && s2idle_ops->wake) { + if (s2idle_ops->wake()) + break; + } else if (pm_wakeup_pending()) { break; + } pm_wakeup_clear(false);