From patchwork Thu Jan 27 21:19:54 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rafael J. Wysocki" X-Patchwork-Id: 513221 Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [140.211.169.13]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p0RLMUSs030037 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 27 Jan 2011 21:22:51 GMT Received: from daredevil.linux-foundation.org (localhost [127.0.0.1]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p0RLJx8q001826; Thu, 27 Jan 2011 13:20:00 -0800 Received: from nat.nue.novell.com (charybdis-ext.suse.de [195.135.221.2]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p0RLJsfB001808 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 27 Jan 2011 13:19:56 -0800 Received: from ferrari.rjw.lan (220-bem-13.acn.waw.pl [82.210.184.220]) by nat.nue.novell.com with ESMTP (TLS encrypted); Thu, 27 Jan 2011 22:19:52 +0100 From: "Rafael J. Wysocki" Organization: Novell Inc. To: Alan Stern Date: Thu, 27 Jan 2011 22:19:54 +0100 User-Agent: KMail/1.13.5 (Linux/2.6.38-rc2+; KDE/4.4.4; x86_64; ; ) References: In-Reply-To: MIME-Version: 1.0 Message-Id: <201101272219.54303.rjw@novell.com> Received-SPF: pass (localhost is always allowed.) X-Spam-Status: No, hits=-103.912 required=5 tests=AWL, BAYES_00, OSDL_HEADER_SUBJECT_BRACKETED, USER_IN_WHITELIST X-Spam-Checker-Version: SpamAssassin 3.2.4-osdl_revision__1.47__ X-MIMEDefang-Filter: lf$Revision: 1.188 $ X-Scanned-By: MIMEDefang 2.63 on 140.211.169.21 Cc: Linux-pm mailing list , LKML Subject: Re: [linux-pm] [PATCH 1/3] PM / Wakeup: Add missing memory barriers X-BeenThere: linux-pm@lists.linux-foundation.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux power management List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-pm-bounces@lists.linux-foundation.org Errors-To: linux-pm-bounces@lists.linux-foundation.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 27 Jan 2011 21:22:51 +0000 (UTC) Index: linux-2.6/drivers/base/power/wakeup.c =================================================================== --- linux-2.6.orig/drivers/base/power/wakeup.c +++ linux-2.6/drivers/base/power/wakeup.c @@ -24,12 +24,26 @@ */ bool events_check_enabled; -/* The counter of registered wakeup events. */ -static atomic_t event_count = ATOMIC_INIT(0); -/* A preserved old value of event_count. */ +/* + * Combined counters of registered wakeup events and wakeup events in progress. + * They need to be modified together atomically, so it's better to use one + * atomic variable to hold them both. + */ +static atomic_t combined_event_count = ATOMIC_INIT(0); + +#define IN_PROGRESS_BITS (sizeof(int) * 4) +#define MAX_IN_PROGRESS ((1 << IN_PROGRESS_BITS) - 1) + +static void split_counters(unsigned int *cnt, unsigned int *inpr) +{ + unsigned int comb = atomic_read(&combined_event_count); + + *cnt = (comb >> IN_PROGRESS_BITS); + *inpr = comb & MAX_IN_PROGRESS; +} + +/* A preserved old value of the events counter. */ static unsigned int saved_count; -/* The counter of wakeup events being processed. */ -static atomic_t events_in_progress = ATOMIC_INIT(0); static DEFINE_SPINLOCK(events_lock); @@ -333,7 +347,8 @@ static void wakeup_source_activate(struc ws->timer_expires = jiffies; ws->last_time = ktime_get(); - atomic_inc(&events_in_progress); + /* Increment the counter of events in progress. */ + atomic_inc(&combined_event_count); } /** @@ -420,14 +435,10 @@ static void wakeup_source_deactivate(str del_timer(&ws->timer); /* - * event_count has to be incremented before events_in_progress is - * modified, so that the callers of pm_check_wakeup_events() and - * pm_save_wakeup_count() don't see the old value of event_count and - * events_in_progress equal to zero at the same time. + * Increment the counter of registered wakeup events and decrement the + * couter of wakeup events in progress simultaneously. */ - atomic_inc(&event_count); - smp_mb__before_atomic_dec(); - atomic_dec(&events_in_progress); + atomic_add(MAX_IN_PROGRESS, &combined_event_count); } /** @@ -582,8 +593,10 @@ bool pm_wakeup_pending(void) spin_lock_irqsave(&events_lock, flags); if (events_check_enabled) { - ret = ((unsigned int)atomic_read(&event_count) != saved_count) - || atomic_read(&events_in_progress); + unsigned int cnt, inpr; + + split_counters(&cnt, &inpr); + ret = (cnt != saved_count || inpr > 0); events_check_enabled = !ret; } spin_unlock_irqrestore(&events_lock, flags); @@ -605,19 +618,22 @@ bool pm_wakeup_pending(void) */ bool pm_get_wakeup_count(unsigned int *count) { - bool ret; + unsigned int cnt, inpr; if (capable(CAP_SYS_ADMIN)) events_check_enabled = false; - while (atomic_read(&events_in_progress) && !signal_pending(current)) { + for (;;) { + split_counters(&cnt, &inpr); + if (inpr == 0 || signal_pending(current)) + break; pm_wakeup_update_hit_counts(); schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); } - ret = !atomic_read(&events_in_progress); - *count = atomic_read(&event_count); - return ret; + split_counters(&cnt, &inpr); + *count = cnt; + return !inpr; } /** @@ -631,11 +647,12 @@ bool pm_get_wakeup_count(unsigned int *c */ bool pm_save_wakeup_count(unsigned int count) { + unsigned int cnt, inpr; bool ret = false; spin_lock_irq(&events_lock); - if (count == (unsigned int)atomic_read(&event_count) - && !atomic_read(&events_in_progress)) { + split_counters(&cnt, &inpr); + if (cnt == count && inpr == 0) { saved_count = count; events_check_enabled = true; ret = true;