diff options
author | Colin Cross <ccross@android.com> | 2011-06-29 13:54:42 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-06-29 13:54:42 -0700 |
commit | e55d4fa96762fd767a3b6d842c904e994db6bb2e (patch) | |
tree | c74157e01cb128cb97f106a50cfadc4c8b872c41 /drivers/char | |
parent | e32c14667e4fe9f16ac9b918d15d29abd2315a55 (diff) | |
parent | b0af8dfdd67699e25083478c63eedef2e72ebd85 (diff) | |
download | kernel_samsung_tuna-e55d4fa96762fd767a3b6d842c904e994db6bb2e.zip kernel_samsung_tuna-e55d4fa96762fd767a3b6d842c904e994db6bb2e.tar.gz kernel_samsung_tuna-e55d4fa96762fd767a3b6d842c904e994db6bb2e.tar.bz2 |
Merge commit 'v3.0-rc5' into android-3.0
Diffstat (limited to 'drivers/char')
-rw-r--r-- | 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) |