diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-07-31 12:43:41 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-31 12:43:41 -0400 |
commit | 85e9ca333d03fbd56b9e123c8456f0d98e20faad (patch) | |
tree | 7bb15ada5f536950efa23ad60ea9eea60380ca1c /arch/x86/kernel/hpet.c | |
parent | a300bec952127d9a15e666b391bb35c9aecb3002 (diff) | |
parent | 6e86841d05f371b5b9b86ce76c02aaee83352298 (diff) |
Merge branch 'linus' into timers/hpet
Diffstat (limited to 'arch/x86/kernel/hpet.c')
-rw-r--r-- | arch/x86/kernel/hpet.c | 73 |
1 files changed, 29 insertions, 44 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 9b5cfcdfc426..ad2b15a1334d 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | /* FSEC = 10^-15 | 18 | /* FSEC = 10^-15 |
19 | NSEC = 10^-9 */ | 19 | NSEC = 10^-9 */ |
20 | #define FSEC_PER_NSEC 1000000 | 20 | #define FSEC_PER_NSEC 1000000L |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * HPET address is set in acpi/boot.c, when an ACPI entry exists | 23 | * HPET address is set in acpi/boot.c, when an ACPI entry exists |
@@ -36,26 +36,15 @@ static inline void hpet_writel(unsigned long d, unsigned long a) | |||
36 | } | 36 | } |
37 | 37 | ||
38 | #ifdef CONFIG_X86_64 | 38 | #ifdef CONFIG_X86_64 |
39 | |||
40 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
41 | 40 | #endif | |
42 | static inline void hpet_set_mapping(void) | ||
43 | { | ||
44 | set_fixmap_nocache(FIX_HPET_BASE, hpet_address); | ||
45 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); | ||
46 | hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); | ||
47 | } | ||
48 | |||
49 | static inline void hpet_clear_mapping(void) | ||
50 | { | ||
51 | hpet_virt_address = NULL; | ||
52 | } | ||
53 | |||
54 | #else | ||
55 | 41 | ||
56 | static inline void hpet_set_mapping(void) | 42 | static inline void hpet_set_mapping(void) |
57 | { | 43 | { |
58 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); | 44 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); |
45 | #ifdef CONFIG_X86_64 | ||
46 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); | ||
47 | #endif | ||
59 | } | 48 | } |
60 | 49 | ||
61 | static inline void hpet_clear_mapping(void) | 50 | static inline void hpet_clear_mapping(void) |
@@ -63,7 +52,6 @@ static inline void hpet_clear_mapping(void) | |||
63 | iounmap(hpet_virt_address); | 52 | iounmap(hpet_virt_address); |
64 | hpet_virt_address = NULL; | 53 | hpet_virt_address = NULL; |
65 | } | 54 | } |
66 | #endif | ||
67 | 55 | ||
68 | /* | 56 | /* |
69 | * HPET command line enable / disable | 57 | * HPET command line enable / disable |
@@ -206,20 +194,19 @@ static void hpet_enable_legacy_int(void) | |||
206 | 194 | ||
207 | static void hpet_legacy_clockevent_register(void) | 195 | static void hpet_legacy_clockevent_register(void) |
208 | { | 196 | { |
209 | uint64_t hpet_freq; | ||
210 | |||
211 | /* Start HPET legacy interrupts */ | 197 | /* Start HPET legacy interrupts */ |
212 | hpet_enable_legacy_int(); | 198 | hpet_enable_legacy_int(); |
213 | 199 | ||
214 | /* | 200 | /* |
215 | * The period is a femto seconds value. We need to calculate the | 201 | * The mult factor is defined as (include/linux/clockchips.h) |
216 | * scaled math multiplication factor for nanosecond to hpet tick | 202 | * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) |
217 | * conversion. | 203 | * hpet_period is in units of femtoseconds (per cycle), so |
204 | * mult/2^shift = cyc/ns = 10^6/hpet_period | ||
205 | * mult = (10^6 * 2^shift)/hpet_period | ||
206 | * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period | ||
218 | */ | 207 | */ |
219 | hpet_freq = 1000000000000000ULL; | 208 | hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, |
220 | do_div(hpet_freq, hpet_period); | 209 | hpet_period, hpet_clockevent.shift); |
221 | hpet_clockevent.mult = div_sc((unsigned long) hpet_freq, | ||
222 | NSEC_PER_SEC, hpet_clockevent.shift); | ||
223 | /* Calculate the min / max delta */ | 210 | /* Calculate the min / max delta */ |
224 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | 211 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, |
225 | &hpet_clockevent); | 212 | &hpet_clockevent); |
@@ -324,7 +311,7 @@ static struct clocksource clocksource_hpet = { | |||
324 | 311 | ||
325 | static int hpet_clocksource_register(void) | 312 | static int hpet_clocksource_register(void) |
326 | { | 313 | { |
327 | u64 tmp, start, now; | 314 | u64 start, now; |
328 | cycle_t t1; | 315 | cycle_t t1; |
329 | 316 | ||
330 | /* Start the counter */ | 317 | /* Start the counter */ |
@@ -351,21 +338,15 @@ static int hpet_clocksource_register(void) | |||
351 | return -ENODEV; | 338 | return -ENODEV; |
352 | } | 339 | } |
353 | 340 | ||
354 | /* Initialize and register HPET clocksource | 341 | /* |
355 | * | 342 | * The definition of mult is (include/linux/clocksource.h) |
356 | * hpet period is in femto seconds per cycle | 343 | * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc |
357 | * so we need to convert this to ns/cyc units | 344 | * so we first need to convert hpet_period to ns/cyc units: |
358 | * approximated by mult/2^shift | 345 | * mult/2^shift = ns/cyc = hpet_period/10^6 |
359 | * | 346 | * mult = (hpet_period * 2^shift)/10^6 |
360 | * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift | 347 | * mult = (hpet_period << shift)/FSEC_PER_NSEC |
361 | * fsec/cyc * 1ns/1000000fsec * 2^shift = mult | ||
362 | * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult | ||
363 | * (fsec/cyc << shift)/1000000 = mult | ||
364 | * (hpet_period << shift)/FSEC_PER_NSEC = mult | ||
365 | */ | 348 | */ |
366 | tmp = (u64)hpet_period << HPET_SHIFT; | 349 | clocksource_hpet.mult = div_sc(hpet_period, FSEC_PER_NSEC, HPET_SHIFT); |
367 | do_div(tmp, FSEC_PER_NSEC); | ||
368 | clocksource_hpet.mult = (u32)tmp; | ||
369 | 350 | ||
370 | clocksource_register(&clocksource_hpet); | 351 | clocksource_register(&clocksource_hpet); |
371 | 352 | ||
@@ -487,7 +468,7 @@ void hpet_disable(void) | |||
487 | #define RTC_NUM_INTS 1 | 468 | #define RTC_NUM_INTS 1 |
488 | 469 | ||
489 | static unsigned long hpet_rtc_flags; | 470 | static unsigned long hpet_rtc_flags; |
490 | static unsigned long hpet_prev_update_sec; | 471 | static int hpet_prev_update_sec; |
491 | static struct rtc_time hpet_alarm_time; | 472 | static struct rtc_time hpet_alarm_time; |
492 | static unsigned long hpet_pie_count; | 473 | static unsigned long hpet_pie_count; |
493 | static unsigned long hpet_t1_cmp; | 474 | static unsigned long hpet_t1_cmp; |
@@ -594,6 +575,9 @@ int hpet_set_rtc_irq_bit(unsigned long bit_mask) | |||
594 | 575 | ||
595 | hpet_rtc_flags |= bit_mask; | 576 | hpet_rtc_flags |= bit_mask; |
596 | 577 | ||
578 | if ((bit_mask & RTC_UIE) && !(oldbits & RTC_UIE)) | ||
579 | hpet_prev_update_sec = -1; | ||
580 | |||
597 | if (!oldbits) | 581 | if (!oldbits) |
598 | hpet_rtc_timer_init(); | 582 | hpet_rtc_timer_init(); |
599 | 583 | ||
@@ -671,7 +655,7 @@ static void hpet_rtc_timer_reinit(void) | |||
671 | if (hpet_rtc_flags & RTC_PIE) | 655 | if (hpet_rtc_flags & RTC_PIE) |
672 | hpet_pie_count += lost_ints; | 656 | hpet_pie_count += lost_ints; |
673 | if (printk_ratelimit()) | 657 | if (printk_ratelimit()) |
674 | printk(KERN_WARNING "rtc: lost %d interrupts\n", | 658 | printk(KERN_WARNING "hpet1: lost %d rtc interrupts\n", |
675 | lost_ints); | 659 | lost_ints); |
676 | } | 660 | } |
677 | } | 661 | } |
@@ -689,7 +673,8 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) | |||
689 | 673 | ||
690 | if (hpet_rtc_flags & RTC_UIE && | 674 | if (hpet_rtc_flags & RTC_UIE && |
691 | curr_time.tm_sec != hpet_prev_update_sec) { | 675 | curr_time.tm_sec != hpet_prev_update_sec) { |
692 | rtc_int_flag = RTC_UF; | 676 | if (hpet_prev_update_sec >= 0) |
677 | rtc_int_flag = RTC_UF; | ||
693 | hpet_prev_update_sec = curr_time.tm_sec; | 678 | hpet_prev_update_sec = curr_time.tm_sec; |
694 | } | 679 | } |
695 | 680 | ||