Received: by 2002:a25:1506:0:0:0:0:0 with SMTP id 6csp6214212ybv; Tue, 18 Feb 2020 12:09:42 -0800 (PST) X-Google-Smtp-Source: APXvYqwW9BEnKdBaT8N3NI0/7qzWO9QVcNThPLsRAfVOoqoj+xPVqXXqDPvb/TmqSBxX1BWBy953 X-Received: by 2002:a9d:6a06:: with SMTP id g6mr15696169otn.305.1582056582653; Tue, 18 Feb 2020 12:09:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1582056582; cv=none; d=google.com; s=arc-20160816; b=WNEjxuziooTsB43qCRBvns4f66CgdeqZo0YZ68dgvZVWwv6EiDTe9V6ma0nvlhjlhu d1PmXyk1ceIpwrIb5xXGBHA8BLZj6wkqKEJRAWkd1qciPfxkbPBZocDDXsE38W4SphSc sTVkZEwYZutuHoabL+0ITftWUPogStUTze+2V+L6kepuv+K4bwlbXpVwc+ViR7qHX3hK XVmbSOWZgJnrVlI6I4n+H8VMXKzG5gCXccmidmi7XLxi/07NTj+CbQ0OotMXsmpPEGTS iiBV5WNHELDdnQQcUUkzBasqp7TEs22UQPG/5J7tr7IfL3OMj5OiyB0nh50Jwv4/3Lbc 9NnQ== 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 :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=xSWu71NbGSF1QAAAGfkqXEkHBe9TVpdnJZsanmNP6hU=; b=sWdgpKMpl1rHxxNxDHYXyJOQbQP6DHdIKtrCFvJFKPu7mGZqeORNF9iPoSaeYD1OO4 f6z/JLUlT3JbXxToWeu+PmXB7qxFYd6xMYApv8tu19FSX8+0KxyJJgjdeBU3NHoEEvzu JuaVqGoZDZCPsIFV9JKdxaeP/MYTx+bSNDwP3V+tD/sJR/Dmx+POgWW621hTXnDHaFRm OR94k+/aQYcL4v2ZLI7P9tN9C53TxIqvb9uQqotWRq8INXk4ahmbbqd7vX/F/1+B2trN xQcVWigZsfVdAde2k2sf5s2UdhM20WH9j++3KvgJalNkGDt9sAZ8wpsd83VmYgJON3BH 8O1w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=msO80TW+; 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 x2si2349541otk.29.2020.02.18.12.09.30; Tue, 18 Feb 2020 12:09:42 -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; dkim=pass header.i=@kernel.org header.s=default header.b=msO80TW+; 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 S1728085AbgBRT56 (ORCPT + 99 others); Tue, 18 Feb 2020 14:57:58 -0500 Received: from mail.kernel.org ([198.145.29.99]:35374 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727233AbgBRT5z (ORCPT ); Tue, 18 Feb 2020 14:57:55 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 227E22465A; Tue, 18 Feb 2020 19:57:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1582055874; bh=FpIz84TeGZcaSOVcwGGUp7CVd0vgtjsxOYV2MUZX6v0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=msO80TW+vKBINtMGXhtZSg/QFUPXcxx6/5JM/rdJUpzoZrO7clkUQNQdZedb6rm9f u2xPVksnK26KPTWkGWsTEUKR6RpFgPHddq25M/iqQ4JBCmR9hpReLsvZlN9lWmBUiU zlPDYNhid1wh+XHnPiFa3few2Cws3KLB1bO6RsDw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "Rafael J. Wysocki" Subject: [PATCH 5.4 08/66] ACPI: EC: Fix flushing of pending work Date: Tue, 18 Feb 2020 20:54:35 +0100 Message-Id: <20200218190428.879663812@linuxfoundation.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200218190428.035153861@linuxfoundation.org> References: <20200218190428.035153861@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Rafael J. Wysocki commit f0ac20c3f6137910c8a927953e8a92f5b3716166 upstream. Commit 016b87ca5c8c ("ACPI: EC: Rework flushing of pending work") introduced a subtle bug into the flushing of pending EC work while suspended to idle, which may cause the EC driver to fail to re-enable the EC GPE after handling a non-wakeup event (like a battery status change event, for example). The problem is that the work item flushed by flush_scheduled_work() in __acpi_ec_flush_work() may disable the EC GPE and schedule another work item expected to re-enable it, but that new work item is not flushed, so __acpi_ec_flush_work() returns with the EC GPE disabled and the CPU running it goes into an idle state subsequently. If all of the other CPUs are in idle states at that point, the EC GPE won't be re-enabled until at least one CPU is woken up by another interrupt source, so system wakeup events that would normally come from the EC then don't work. This is reproducible on a Dell XPS13 9360 in my office which sometimes stops reacting to power button and lid events (triggered by the EC on that machine) after switching from AC power to battery power or vice versa while suspended to idle (each of those switches causes the EC GPE to trigger for several times in a row, but they are not system wakeup events). To avoid this problem, it is necessary to drain the workqueue entirely in __acpi_ec_flush_work(), but that cannot be done with respect to system_wq, because work items may be added to it from other places while __acpi_ec_flush_work() is running. For this reason, make the EC driver use a dedicated workqueue for EC events processing (let that workqueue be ordered so that EC events are processed sequentially) and use drain_workqueue() on it in __acpi_ec_flush_work(). Fixes: 016b87ca5c8c ("ACPI: EC: Rework flushing of pending work") Cc: 5.4+ # 5.4+ Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ec.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -179,6 +179,7 @@ EXPORT_SYMBOL(first_ec); static struct acpi_ec *boot_ec; static bool boot_ec_is_ecdt = false; +static struct workqueue_struct *ec_wq; static struct workqueue_struct *ec_query_wq; static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ @@ -461,7 +462,7 @@ static void acpi_ec_submit_query(struct ec_dbg_evt("Command(%s) submitted/blocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); ec->nr_pending_queries++; - schedule_work(&ec->work); + queue_work(ec_wq, &ec->work); } } @@ -527,7 +528,7 @@ static void acpi_ec_enable_event(struct #ifdef CONFIG_PM_SLEEP static void __acpi_ec_flush_work(void) { - flush_scheduled_work(); /* flush ec->work */ + drain_workqueue(ec_wq); /* flush ec->work */ flush_workqueue(ec_query_wq); /* flush queries */ } @@ -548,8 +549,8 @@ static void acpi_ec_disable_event(struct void acpi_ec_flush_work(void) { - /* Without ec_query_wq there is nothing to flush. */ - if (!ec_query_wq) + /* Without ec_wq there is nothing to flush. */ + if (!ec_wq) return; __acpi_ec_flush_work(); @@ -2032,25 +2033,33 @@ static struct acpi_driver acpi_ec_driver .drv.pm = &acpi_ec_pm, }; -static inline int acpi_ec_query_init(void) +static void acpi_ec_destroy_workqueues(void) { - if (!ec_query_wq) { - ec_query_wq = alloc_workqueue("kec_query", 0, - ec_max_queries); - if (!ec_query_wq) - return -ENODEV; + if (ec_wq) { + destroy_workqueue(ec_wq); + ec_wq = NULL; } - return 0; -} - -static inline void acpi_ec_query_exit(void) -{ if (ec_query_wq) { destroy_workqueue(ec_query_wq); ec_query_wq = NULL; } } +static int acpi_ec_init_workqueues(void) +{ + if (!ec_wq) + ec_wq = alloc_ordered_workqueue("kec", 0); + + if (!ec_query_wq) + ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries); + + if (!ec_wq || !ec_query_wq) { + acpi_ec_destroy_workqueues(); + return -ENODEV; + } + return 0; +} + static const struct dmi_system_id acpi_ec_no_wakeup[] = { { .ident = "Thinkpad X1 Carbon 6th", @@ -2081,8 +2090,7 @@ int __init acpi_ec_init(void) int result; int ecdt_fail, dsdt_fail; - /* register workqueue for _Qxx evaluations */ - result = acpi_ec_query_init(); + result = acpi_ec_init_workqueues(); if (result) return result; @@ -2113,6 +2121,6 @@ static void __exit acpi_ec_exit(void) { acpi_bus_unregister_driver(&acpi_ec_driver); - acpi_ec_query_exit(); + acpi_ec_destroy_workqueues(); } #endif /* 0 */