diff options
Diffstat (limited to 'arch/x86/kernel/hpet.c')
| -rw-r--r-- | arch/x86/kernel/hpet.c | 24 | 
1 files changed, 20 insertions, 4 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 648b3a2a3a4..81408b93f88 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -236,6 +236,10 @@ static void hpet_stop_counter(void)  	unsigned long cfg = hpet_readl(HPET_CFG);  	cfg &= ~HPET_CFG_ENABLE;  	hpet_writel(cfg, HPET_CFG); +} + +static void hpet_reset_counter(void) +{  	hpet_writel(0, HPET_COUNTER);  	hpet_writel(0, HPET_COUNTER + 4);  } @@ -250,6 +254,7 @@ static void hpet_start_counter(void)  static void hpet_restart_counter(void)  {  	hpet_stop_counter(); +	hpet_reset_counter();  	hpet_start_counter();  } @@ -309,7 +314,7 @@ 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; +	unsigned long cfg, cmp, now;  	uint64_t delta;  	switch (mode) { @@ -317,12 +322,23 @@ static void hpet_set_mode(enum clock_event_mode mode,  		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)); +		hpet_writel(cmp, HPET_Tn_CMP(timer)); +		udelay(1); +		/* +		 * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL +		 * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL +		 * bit is automatically cleared after the first write. +		 * (See AMD-8111 HyperTransport I/O Hub Data Sheet, +		 * Publication # 24674) +		 */  		hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));  		hpet_start_counter();  		hpet_print_config(); @@ -722,7 +738,7 @@ static int hpet_cpuhp_notify(struct notifier_block *n,  /*   * Clock source related code   */ -static cycle_t read_hpet(void) +static cycle_t read_hpet(struct clocksource *cs)  {  	return (cycle_t)hpet_readl(HPET_COUNTER);  } @@ -756,7 +772,7 @@ static int hpet_clocksource_register(void)  	hpet_restart_counter();  	/* Verify whether hpet counter works */ -	t1 = read_hpet(); +	t1 = hpet_readl(HPET_COUNTER);  	rdtscll(start);  	/* @@ -770,7 +786,7 @@ static int hpet_clocksource_register(void)  		rdtscll(now);  	} while ((now - start) < 200000UL); -	if (t1 == read_hpet()) { +	if (t1 == hpet_readl(HPET_COUNTER)) {  		printk(KERN_WARNING  		       "HPET counter not counting. HPET disabled\n");  		return -ENODEV;  |