aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/hpet.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-09-14 12:24:00 -0400
committerIngo Molnar <mingo@elte.hu>2008-09-14 12:24:00 -0400
commit83bd6998b04fc1bb7280b14f16b2bdbdc07c914b (patch)
treeaf1bbe2bac5752b69b1ac58bf5d822c735da439b /arch/x86/kernel/hpet.c
parente7250b8ae3870f37f660c2f65cafcaba85e3bfd3 (diff)
parentadee14b2e1557d0a8559f29681732d05a89dfc35 (diff)
Merge commit 'v2.6.27-rc6' into timers/hpet
Diffstat (limited to 'arch/x86/kernel/hpet.c')
-rw-r--r--arch/x86/kernel/hpet.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 82d459186fd..acf62fc233d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -214,8 +214,8 @@ static void hpet_legacy_clockevent_register(void)
214 /* Calculate the min / max delta */ 214 /* Calculate the min / max delta */
215 hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, 215 hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
216 &hpet_clockevent); 216 &hpet_clockevent);
217 hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, 217 /* 5 usec minimum reprogramming delta. */
218 &hpet_clockevent); 218 hpet_clockevent.min_delta_ns = 5000;
219 219
220 /* 220 /*
221 * Start hpet with the boot cpu mask and make it 221 * Start hpet with the boot cpu mask and make it
@@ -274,15 +274,22 @@ static void hpet_legacy_set_mode(enum clock_event_mode mode,
274} 274}
275 275
276static int hpet_legacy_next_event(unsigned long delta, 276static int hpet_legacy_next_event(unsigned long delta,
277 struct clock_event_device *evt) 277 struct clock_event_device *evt)
278{ 278{
279 unsigned long cnt; 279 u32 cnt;
280 280
281 cnt = hpet_readl(HPET_COUNTER); 281 cnt = hpet_readl(HPET_COUNTER);
282 cnt += delta; 282 cnt += (u32) delta;
283 hpet_writel(cnt, HPET_T0_CMP); 283 hpet_writel(cnt, HPET_T0_CMP);
284 284
285 return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0) ? -ETIME : 0; 285 /*
286 * We need to read back the CMP register to make sure that
287 * what we wrote hit the chip before we compare it to the
288 * counter.
289 */
290 WARN_ON((u32)hpet_readl(HPET_T0_CMP) != cnt);
291
292 return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
286} 293}
287 294
288/* 295/*
@@ -363,6 +370,7 @@ static int hpet_clocksource_register(void)
363int __init hpet_enable(void) 370int __init hpet_enable(void)
364{ 371{
365 unsigned long id; 372 unsigned long id;
373 int i;
366 374
367 if (!is_hpet_capable()) 375 if (!is_hpet_capable())
368 return 0; 376 return 0;
@@ -373,6 +381,29 @@ int __init hpet_enable(void)
373 * Read the period and check for a sane value: 381 * Read the period and check for a sane value:
374 */ 382 */
375 hpet_period = hpet_readl(HPET_PERIOD); 383 hpet_period = hpet_readl(HPET_PERIOD);
384
385 /*
386 * AMD SB700 based systems with spread spectrum enabled use a
387 * SMM based HPET emulation to provide proper frequency
388 * setting. The SMM code is initialized with the first HPET
389 * register access and takes some time to complete. During
390 * this time the config register reads 0xffffffff. We check
391 * for max. 1000 loops whether the config register reads a non
392 * 0xffffffff value to make sure that HPET is up and running
393 * before we go further. A counting loop is safe, as the HPET
394 * access takes thousands of CPU cycles. On non SB700 based
395 * machines this check is only done once and has no side
396 * effects.
397 */
398 for (i = 0; hpet_readl(HPET_CFG) == 0xFFFFFFFF; i++) {
399 if (i == 1000) {
400 printk(KERN_WARNING
401 "HPET config register value = 0xFFFFFFFF. "
402 "Disabling HPET\n");
403 goto out_nohpet;
404 }
405 }
406
376 if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) 407 if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
377 goto out_nohpet; 408 goto out_nohpet;
378 409