summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Herrmann <andreas.herrmann3@amd.com>2009-05-29 17:35:14 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-15 09:40:21 -0700
commit5beb01f947a1607c094f053d6575b4f647b7016c (patch)
treecbd2d43931fc5a2fdceba9588405b18c553fba5b
parent8c68c89bc518df5fb21112be68c94fcd25b8b2de (diff)
x86: hpet: stop HPET_COUNTER when programming periodic mode
commit c23e253e67c9d8a91a0ffa33c1f571a17f0a2403 upstream x86: hpet: stop HPET_COUNTER when programming periodic mode Impact: fix system hang on some systems operating with HZ_1000 On a system that stalled with HZ_1000, the first value written to T0_CMP (when the main counter was not stopped) did not trigger an interrupt. Instead after the main counter wrapped around (after several minutes) an interrupt was triggered and afterwards the periodic interrupt took effect. This can be fixed by implementing HPET spec recommendation for programming the periodic mode (i.e. stopping the main counter). [cebbert@redhat.com: backport to 2.6.29] Signed-off-by: Andreas Herrmann <andreas.herrmann3@amd.com> Cc: Mark Hounschell <markh@compro.net> Cc: Borislav Petkov <borislav.petkov@amd.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: Chuck Ebbert <cebbert@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--arch/x86/kernel/hpet.c13
1 files changed, 3 insertions, 10 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 8ad753232b56..a54d2718541a 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -269,29 +269,22 @@ static int hpet_setup_msi_irq(unsigned int irq);
static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt, int timer)
{
- unsigned long cfg, cmp, now;
+ unsigned long cfg;
uint64_t delta;
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
+ hpet_stop_counter();
delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult;
delta >>= evt->shift;
- now = hpet_readl(HPET_COUNTER);
- cmp = now + (unsigned long) delta;
cfg = hpet_readl(HPET_Tn_CFG(timer));
/* Make sure we use edge triggered interrupts */
cfg &= ~HPET_TN_LEVEL;
cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
HPET_TN_SETVAL | HPET_TN_32BIT;
hpet_writel(cfg, HPET_Tn_CFG(timer));
- /*
- * The first write after writing TN_SETVAL to the
- * config register sets the counter value, the second
- * write sets the period.
- */
- hpet_writel(cmp, HPET_Tn_CMP(timer));
- udelay(1);
hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
+ hpet_start_counter();
break;
case CLOCK_EVT_MODE_ONESHOT: