From patchwork Tue Feb 2 20:23:33 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 76507 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o12KMlcL022217 for ; Tue, 2 Feb 2010 20:22:59 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753754Ab0BBUW6 (ORCPT ); Tue, 2 Feb 2010 15:22:58 -0500 Received: from ogre.sisk.pl ([217.79.144.158]:36190 "EHLO ogre.sisk.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753728Ab0BBUW5 convert rfc822-to-8bit (ORCPT ); Tue, 2 Feb 2010 15:22:57 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id 1D15C174E10; Tue, 2 Feb 2010 21:08:23 +0100 (CET) Received: from ogre.sisk.pl ([127.0.0.1]) by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 01519-04; Tue, 2 Feb 2010 21:08:15 +0100 (CET) Received: from tosh.localnet (220-bem-13.acn.waw.pl [82.210.184.220]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ogre.sisk.pl (Postfix) with ESMTP id 85E271679F4; Tue, 2 Feb 2010 21:08:15 +0100 (CET) From: "Rafael J. Wysocki" To: Alexey Starikovskiy Subject: [PATCH] ACPI / EC: Remover race between EC driver and suspend process (was: Re: [RFC][RFT][PATCH] ACPI: Protection from suspending in the middle of EC transaction) Date: Tue, 2 Feb 2010 21:23:33 +0100 User-Agent: KMail/1.12.4 (Linux/2.6.33-rc6-rjw; KDE/4.3.5; x86_64; ; ) Cc: Henrique de Moraes Holschuh , Maxim Levitsky , Alan Jenkins , ACPI Devel Maling List , Len Brown , pm list , Thomas Renninger , Matthew Garrett , LKML References: <201001310029.48717.rjw@sisk.pl> <4B66AB7F.7050908@suse.de> <201002012342.50074.rjw@sisk.pl> In-Reply-To: <201002012342.50074.rjw@sisk.pl> MIME-Version: 1.0 Message-Id: <201002022123.34061.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 02 Feb 2010 20:22:59 +0000 (UTC) Index: linux-2.6/drivers/acpi/ec.c =================================================================== --- linux-2.6.orig/drivers/acpi/ec.c +++ linux-2.6/drivers/acpi/ec.c @@ -76,8 +76,9 @@ enum ec_command { enum { EC_FLAGS_QUERY_PENDING, /* Query is pending */ EC_FLAGS_GPE_STORM, /* GPE storm detected */ - EC_FLAGS_HANDLERS_INSTALLED /* Handlers for GPE and + EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ + EC_FLAGS_SUSPENDED, /* Driver is suspended */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -291,6 +292,10 @@ static int acpi_ec_transaction(struct ac if (t->rdata) memset(t->rdata, 0, t->rlen); mutex_lock(&ec->lock); + if (test_bit(EC_FLAGS_SUSPENDED, &ec->flags)) { + status = -EBUSY; + goto unlock; + } if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) { @@ -445,6 +450,32 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); +void acpi_ec_suspend_transactions(void) +{ + struct acpi_ec *ec = first_ec; + + if (!ec) + return; + + mutex_lock(&ec->lock); + /* Prevent transactions from happening while suspended */ + set_bit(EC_FLAGS_SUSPENDED, &ec->flags); + mutex_unlock(&ec->lock); +} + +void acpi_ec_resume_transactions(void) +{ + struct acpi_ec *ec = first_ec; + + if (!ec) + return; + + mutex_lock(&ec->lock); + /* Allow transactions to happen again */ + clear_bit(EC_FLAGS_SUSPENDED, &ec->flags); + mutex_unlock(&ec->lock); +} + static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; Index: linux-2.6/drivers/acpi/internal.h =================================================================== --- linux-2.6.orig/drivers/acpi/internal.h +++ linux-2.6/drivers/acpi/internal.h @@ -49,6 +49,8 @@ void acpi_early_processor_set_pdc(void); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); +void acpi_ec_suspend_transactions(void); +void acpi_ec_resume_transactions(void); /*-------------------------------------------------------------------------- Suspend/Resume Index: linux-2.6/drivers/acpi/sleep.c =================================================================== --- linux-2.6.orig/drivers/acpi/sleep.c +++ linux-2.6/drivers/acpi/sleep.c @@ -112,9 +112,10 @@ void __init acpi_old_suspend_ordering(vo /** * acpi_pm_disable_gpes - Disable the GPEs. */ -static int acpi_pm_disable_gpes(void) +static int acpi_pm_disable_gpes_and_ec(void) { acpi_disable_all_gpes(); + acpi_ec_suspend_transactions(); return 0; } @@ -142,7 +143,8 @@ static int acpi_pm_prepare(void) int error = __acpi_pm_prepare(); if (!error) - acpi_disable_all_gpes(); + acpi_pm_disable_gpes_and_ec(); + return error; } @@ -286,6 +288,12 @@ static int acpi_suspend_enter(suspend_st return ACPI_SUCCESS(status) ? 0 : -EFAULT; } +static void acpi_suspend_finish(void) +{ + acpi_ec_resume_transactions(); + acpi_pm_finish(); +} + static int acpi_suspend_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -307,7 +315,7 @@ static struct platform_suspend_ops acpi_ .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, }; @@ -333,9 +341,9 @@ static int acpi_suspend_begin_old(suspen static struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, - .prepare_late = acpi_pm_disable_gpes, + .prepare_late = acpi_pm_disable_gpes_and_ec, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, .recover = acpi_pm_finish, }; @@ -530,6 +538,7 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { hibernate_nvs_free(); + acpi_ec_resume_transactions(); acpi_pm_finish(); } @@ -552,8 +561,9 @@ static void acpi_hibernation_leave(void) hibernate_nvs_restore(); } -static void acpi_pm_enable_gpes(void) +static void acpi_pm_enable_gpes_and_ec(void) { + acpi_ec_resume_transactions(); acpi_enable_all_runtime_gpes(); } @@ -565,8 +575,8 @@ static struct platform_hibernation_ops a .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, - .pre_restore = acpi_pm_disable_gpes, - .restore_cleanup = acpi_pm_enable_gpes, + .pre_restore = acpi_pm_disable_gpes_and_ec, + .restore_cleanup = acpi_pm_enable_gpes_and_ec, }; /** @@ -598,12 +608,9 @@ static int acpi_hibernation_begin_old(vo static int acpi_hibernation_pre_snapshot_old(void) { - int error = acpi_pm_disable_gpes(); - - if (!error) - hibernate_nvs_save(); - - return error; + acpi_pm_disable_gpes_and_ec(); + hibernate_nvs_save(); + return 0; } /* @@ -615,11 +622,11 @@ static struct platform_hibernation_ops a .end = acpi_pm_end, .pre_snapshot = acpi_hibernation_pre_snapshot_old, .finish = acpi_hibernation_finish, - .prepare = acpi_pm_disable_gpes, + .prepare = acpi_pm_disable_gpes_and_ec, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, - .pre_restore = acpi_pm_disable_gpes, - .restore_cleanup = acpi_pm_enable_gpes, + .pre_restore = acpi_pm_disable_gpes_and_ec, + .restore_cleanup = acpi_pm_enable_gpes_and_ec, .recover = acpi_pm_finish, }; #endif /* CONFIG_HIBERNATION */