From patchwork Wed Jun 30 23:52:03 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 108975 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o5UNrwa8014167 for ; Wed, 30 Jun 2010 23:53:59 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755363Ab0F3Xxo (ORCPT ); Wed, 30 Jun 2010 19:53:44 -0400 Received: from ogre.sisk.pl ([217.79.144.158]:37897 "EHLO ogre.sisk.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752551Ab0F3Xxo (ORCPT ); Wed, 30 Jun 2010 19:53:44 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id 587C9189D27; Thu, 1 Jul 2010 01:40:19 +0200 (CEST) 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 28452-03; Thu, 1 Jul 2010 01:40:12 +0200 (CEST) Received: from ferrari.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 16E051897D4; Thu, 1 Jul 2010 01:40:12 +0200 (CEST) From: "Rafael J. Wysocki" To: Alan Stern Subject: Re: [update] Re: [PATCH] PM: Make it possible to avoid wakeup events from being lost Date: Thu, 1 Jul 2010 01:52:03 +0200 User-Agent: KMail/1.13.3 (Linux/2.6.35-rc3-rjw+; KDE/4.4.3; x86_64; ; ) Cc: linux-pm@lists.linux-foundation.org, Linux Kernel Mailing List , Neil Brown , Matthew Garrett , mark gross <640e9920@gmail.com>, Arve =?iso-8859-1?q?Hj=F8nnev=E5g?= , Dmitry Torokhov , Florian Mickler , linux-pci@vger.kernel.org, Jesse Barnes References: In-Reply-To: MIME-Version: 1.0 Message-Id: <201007010152.03869.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@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]); Wed, 30 Jun 2010 23:53:59 +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 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,12 @@ static unsigned long events_in_progress; static DEFINE_SPINLOCK(events_lock); +static void pm_wakeup_timer_fn(unsigned long data); + +static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0); +static unsigned long events_timer_expires; +static unsigned long delayed_count; + /* * The functions below use the observation that each wakeup event starts a * period in which the system should not be suspended. The moment this period @@ -103,17 +110,23 @@ void pm_relax(void) } /** - * pm_wakeup_work_fn - Deferred closing of a wakeup event. + * pm_wakeup_timer_fn - Deferred closing of a wakeup event. * * Execute pm_relax() for a wakeup event detected in the past and free the * work item object used for queuing up the work. */ -static void pm_wakeup_work_fn(struct work_struct *work) +static void pm_wakeup_timer_fn(unsigned long data) { - struct delayed_work *dwork = to_delayed_work(work); + unsigned long flags; - pm_relax(); - kfree(dwork); + spin_lock_irqsave(&events_lock, flags); + if (events_timer_expires && time_after(jiffies, events_timer_expires)) { + events_in_progress -= delayed_count; + event_count += delayed_count; + delayed_count = 0; + events_timer_expires = 0; + } + spin_unlock_irqrestore(&events_lock, flags); } /** @@ -132,19 +145,31 @@ static void pm_wakeup_work_fn(struct wor void pm_wakeup_event(struct device *dev, unsigned int msec) { unsigned long flags; - struct delayed_work *dwork; - - dwork = msec ? kzalloc(sizeof(*dwork), GFP_ATOMIC) : NULL; spin_lock_irqsave(&events_lock, flags); if (dev) dev->power.wakeup_count++; - if (dwork) { - INIT_DELAYED_WORK(dwork, pm_wakeup_work_fn); - schedule_delayed_work(dwork, msecs_to_jiffies(msec)); + if (msec) { + ktime_t kt; + struct timespec ts; + unsigned long expires; + + kt = ktime_get(); + kt = ktime_add_ns(kt, msec * NSEC_PER_MSEC); + ts = ktime_to_timespec(kt); + expires = timespec_to_jiffies(&ts); + if (!expires) + expires = 1; + + if (!events_timer_expires + || time_after(expires, events_timer_expires)) { + mod_timer(&events_timer, expires); + events_timer_expires = expires; + } events_in_progress++; + delayed_count++; } else { event_count++; }