From patchwork Thu Aug 31 08:10:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lv Zheng X-Patchwork-Id: 9931477 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C307D60362 for ; Thu, 31 Aug 2017 08:11:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A9C3228893 for ; Thu, 31 Aug 2017 08:11:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9EC7328899; Thu, 31 Aug 2017 08:11:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 377E428893 for ; Thu, 31 Aug 2017 08:11:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750781AbdHaILY (ORCPT ); Thu, 31 Aug 2017 04:11:24 -0400 Received: from mga14.intel.com ([192.55.52.115]:20873 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751843AbdHaIKn (ORCPT ); Thu, 31 Aug 2017 04:10:43 -0400 Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 Aug 2017 01:10:29 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.41,451,1498546800"; d="scan'208";a="144009307" Received: from lvzheng-moblsp3.sh.intel.com ([10.239.159.38]) by orsmga005.jf.intel.com with ESMTP; 31 Aug 2017 01:10:27 -0700 From: Lv Zheng To: "Rafael J . Wysocki" , "Rafael J . Wysocki" , Len Brown Cc: Lv Zheng , Lv Zheng , linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org Subject: [PATCH v4 1/3] ACPI / EC: Fix possible driver order issue by moving EC event handling earlier Date: Thu, 31 Aug 2017 16:10:26 +0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: <99f23db65bbe89ee856018629654584a96734c84.1501141963.git.lv.zheng@intel.com> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch tries to detect EC events earlier after resume, so that if an event occurred before invoking acpi_ec_unblock_transactions(), it could be detected by acpi_ec_unblock_transactions() which is the earliest EC driver call after resume. However after the noirq stage, if an event ocurred after acpi_ec_unblock_transactions() and before acpi_ec_resume(), there was no mean to detect and trigger it, finally it could cause EC event handling stuck. Thus this patch also adds a detection in acpi_ec_resume(), trying to recover from the affection of the noirq stage. The background of the affection: EC IRQs contain transaction IRQs (OBF/IBF) and event IRQ (SCI_EVT). 1. Transactions are initiated by hosts. The earliest OSPMs execution of EC transactions is from acpi_ec_transaction(), where the common EC IRQ handling procedure - advance_transaction() - is initiated from the task context. 2. Events are initiated by targets. The earliest OSPMs execution of EC events is from acpi_ec_gpe_handler(), where the common EC IRQ handling procedure - advance_transaction() - is initiated from the IRQ context. During suspend/resume noirq stage, IRQ is disabled, advance_transaction() which detects SCI_EVT can only be invoked from task context - ec_poll(). Thus if there is no EC transaction occurring in this stage, EC driver cannot detect SCI_EVT. And the worst case is if there is no EC transaction after resume, EC event handling will stuck (FW flags SCI_EVT, but there is no triggering source for OS SW to detect it). Now the final logic is: 1. If ec_freeze_events=Y, event handling is stopped in acpi_ec_suspend(), restarted in acpi_ec_resume(); 2. If ec_freeze_events=N, event handling is stopped in acpi_ec_block_transactions(), restarted in acpi_ec_unblock_transactions(); 3. In order to handling the conflict of the edge-trigger nature of EC IRQ and the Linux noirq stage, advance_transaction() is invoked where the event handling is enabled and the noirq stage is ended. Known issue: 1. Event ocurred between acpi_ec_unblock_transactions() and acpi_ec_resume() may still lead to the order issue. This can only be fixed by adding a periodic detection mechanism during the noirq stage. Signed-off-by: Lv Zheng Tested-by: Tomislav Ivek --- drivers/acpi/ec.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index fdfae6f..3dc4205 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -486,8 +486,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec) { if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) ec_log_drv("event unblocked"); - if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - advance_transaction(ec); + /* + * Unconditionally invoke this once after enabling the event + * handling mechanism to detect the pending events. + */ + advance_transaction(ec); } static inline void __acpi_ec_disable_event(struct acpi_ec *ec) @@ -945,7 +948,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) if (!resuming) { acpi_ec_submit_request(ec); ec_dbg_ref(ec, "Increase driver"); - } + } else if (!ec_freeze_events) + __acpi_ec_enable_event(ec); ec_log_drv("EC started"); } spin_unlock_irqrestore(&ec->lock, flags); @@ -1929,7 +1933,18 @@ static int acpi_ec_resume(struct device *dev) struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); - acpi_ec_enable_event(ec); + if (ec_freeze_events) + acpi_ec_enable_event(ec); + else { + /* + * Though whether there is an event pending has been + * checked in acpi_ec_unblock_transactions() when + * ec_freeze_events=N, check it one more time after noirq + * stage to detect events occurred after + * acpi_ec_unblock_transactions(). + */ + advance_transaction(ec); + } return 0; } #endif