From: Nils Carlson <nils.carlson@ericsson.com>
To: <clemens@ladisch.de>, <linux-kernel@vger.kernel.org>
Cc: Nils Carlson <nils.carlson@ericsson.com>
Subject: [PATCH] Fix periodic-emulation in HPET for delayed interrupts
Date: Wed, 1 Jun 2011 13:58:50 +0200 [thread overview]
Message-ID: <1306929530-23771-1-git-send-email-nils.carlson@ericsson.com> (raw)
When interrupts are delayed due to interrupt masking or due
to other interrupts being serviced the HPET periodic-emuation
would fail. This happened because given an interval t and
a time for the current interrupt m we would compute the next
time as t + m. This works until we are delayed for > t, in
which case we would be writing a new value which is in fact
in the past.
This can be solved by computing the next time instead as
(k * t) + m where k is large enough to be in the future.
The exact computation of k is described in a comment to
the code.
Signed-off-by: Nils Carlson <nils.carlson@ericsson.com>
---
drivers/char/hpet.c | 25 +++++++++++++++++++++++--
1 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 051474c..34d6a1c 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -163,11 +163,32 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
* This has the effect of treating non-periodic like periodic.
*/
if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) {
- unsigned long m, t;
+ unsigned long m, t, mc, base, k;
+ struct hpet __iomem *hpet = devp->hd_hpet;
+ struct hpets *hpetp = devp->hd_hpets;
t = devp->hd_ireqfreq;
m = read_counter(&devp->hd_timer->hpet_compare);
- write_counter(t + m, &devp->hd_timer->hpet_compare);
+ mc = read_counter(&hpet->hpet_mc);
+ /* The time for the next interrupt would logically be t + m,
+ * however, if we are very unlucky and the interrupt is delayed
+ * for longer than t then we will completely miss the next
+ * interrupt if we set t + m and an application will hang.
+ * Therefore we need to make a more complex computation assuming
+ * that there exists a k for which the following is true:
+ * k * t + base < mc + delta
+ * (k + 1) * t + base > mc + delta
+ * where t is the interval in hpet ticks for the given freq,
+ * base is the theoretical start value 0 < base < t,
+ * mc is the main counter value at the time of the interrupt,
+ * delta is the time it takes to write the a value to the
+ * comparator.
+ * k may then be computed as (mc - base + delta) / t .
+ */
+ base = mc % t;
+ k = (mc - base + hpetp->hp_delta) / t;
+ write_counter(t * (k + 1) + base,
+ &devp->hd_timer->hpet_compare);
}
if (devp->hd_flags & HPET_SHARED_IRQ)
--
1.7.2.5
next reply other threads:[~2011-06-01 11:48 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-01 11:58 Nils Carlson [this message]
2011-06-08 21:38 ` Andrew Morton
2011-06-09 9:23 ` Nils Carlson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1306929530-23771-1-git-send-email-nils.carlson@ericsson.com \
--to=nils.carlson@ericsson.com \
--cc=clemens@ladisch.de \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®