diff options
-rw-r--r-- | arch/x86/kernel/hpet_32.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet_32.c index 748abf0286d2..dbe0e1d44113 100644 --- a/arch/x86/kernel/hpet_32.c +++ b/arch/x86/kernel/hpet_32.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/clocksource.h> | 1 | #include <linux/clocksource.h> |
2 | #include <linux/clockchips.h> | 2 | #include <linux/clockchips.h> |
3 | #include <linux/delay.h> | ||
3 | #include <linux/errno.h> | 4 | #include <linux/errno.h> |
4 | #include <linux/hpet.h> | 5 | #include <linux/hpet.h> |
5 | #include <linux/init.h> | 6 | #include <linux/init.h> |
@@ -7,6 +8,7 @@ | |||
7 | #include <linux/pm.h> | 8 | #include <linux/pm.h> |
8 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
9 | 10 | ||
11 | #include <asm/fixmap.h> | ||
10 | #include <asm/hpet.h> | 12 | #include <asm/hpet.h> |
11 | #include <asm/i8253.h> | 13 | #include <asm/i8253.h> |
12 | #include <asm/io.h> | 14 | #include <asm/io.h> |
@@ -23,6 +25,10 @@ | |||
23 | unsigned long hpet_address; | 25 | unsigned long hpet_address; |
24 | static void __iomem *hpet_virt_address; | 26 | static void __iomem *hpet_virt_address; |
25 | 27 | ||
28 | /* Temporary hack. Cleanup after x86_64 clock events conversion */ | ||
29 | #undef hpet_readl | ||
30 | #undef hpet_writel | ||
31 | |||
26 | static inline unsigned long hpet_readl(unsigned long a) | 32 | static inline unsigned long hpet_readl(unsigned long a) |
27 | { | 33 | { |
28 | return readl(hpet_virt_address + a); | 34 | return readl(hpet_virt_address + a); |
@@ -33,6 +39,24 @@ static inline void hpet_writel(unsigned long d, unsigned long a) | |||
33 | writel(d, hpet_virt_address + a); | 39 | writel(d, hpet_virt_address + a); |
34 | } | 40 | } |
35 | 41 | ||
42 | #ifdef CONFIG_X86_64 | ||
43 | |||
44 | #include <asm/pgtable.h> | ||
45 | |||
46 | static inline void hpet_set_mapping(void) | ||
47 | { | ||
48 | set_fixmap_nocache(FIX_HPET_BASE, hpet_address); | ||
49 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); | ||
50 | hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); | ||
51 | } | ||
52 | |||
53 | static inline void hpet_clear_mapping(void) | ||
54 | { | ||
55 | hpet_virt_address = NULL; | ||
56 | } | ||
57 | |||
58 | #else | ||
59 | |||
36 | static inline void hpet_set_mapping(void) | 60 | static inline void hpet_set_mapping(void) |
37 | { | 61 | { |
38 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); | 62 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); |
@@ -43,6 +67,7 @@ static inline void hpet_clear_mapping(void) | |||
43 | iounmap(hpet_virt_address); | 67 | iounmap(hpet_virt_address); |
44 | hpet_virt_address = NULL; | 68 | hpet_virt_address = NULL; |
45 | } | 69 | } |
70 | #endif | ||
46 | 71 | ||
47 | /* | 72 | /* |
48 | * HPET command line enable / disable | 73 | * HPET command line enable / disable |
@@ -59,6 +84,13 @@ static int __init hpet_setup(char* str) | |||
59 | } | 84 | } |
60 | __setup("hpet=", hpet_setup); | 85 | __setup("hpet=", hpet_setup); |
61 | 86 | ||
87 | static int __init disable_hpet(char *str) | ||
88 | { | ||
89 | boot_hpet_disable = 1; | ||
90 | return 1; | ||
91 | } | ||
92 | __setup("nohpet", disable_hpet); | ||
93 | |||
62 | static inline int is_hpet_capable(void) | 94 | static inline int is_hpet_capable(void) |
63 | { | 95 | { |
64 | return (!boot_hpet_disable && hpet_address); | 96 | return (!boot_hpet_disable && hpet_address); |
@@ -225,6 +257,13 @@ static cycle_t read_hpet(void) | |||
225 | return (cycle_t)hpet_readl(HPET_COUNTER); | 257 | return (cycle_t)hpet_readl(HPET_COUNTER); |
226 | } | 258 | } |
227 | 259 | ||
260 | #ifdef CONFIG_X86_64 | ||
261 | static cycle_t __vsyscall_fn vread_hpet(void) | ||
262 | { | ||
263 | return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | ||
264 | } | ||
265 | #endif | ||
266 | |||
228 | static struct clocksource clocksource_hpet = { | 267 | static struct clocksource clocksource_hpet = { |
229 | .name = "hpet", | 268 | .name = "hpet", |
230 | .rating = 250, | 269 | .rating = 250, |
@@ -233,6 +272,9 @@ static struct clocksource clocksource_hpet = { | |||
233 | .shift = HPET_SHIFT, | 272 | .shift = HPET_SHIFT, |
234 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 273 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
235 | .resume = hpet_start_counter, | 274 | .resume = hpet_start_counter, |
275 | #ifdef CONFIG_X86_64 | ||
276 | .vread = vread_hpet, | ||
277 | #endif | ||
236 | }; | 278 | }; |
237 | 279 | ||
238 | /* | 280 | /* |
@@ -331,7 +373,6 @@ int __init hpet_enable(void) | |||
331 | 373 | ||
332 | if (id & HPET_ID_LEGSUP) { | 374 | if (id & HPET_ID_LEGSUP) { |
333 | hpet_enable_int(); | 375 | hpet_enable_int(); |
334 | hpet_reserve_platform_timers(id); | ||
335 | /* | 376 | /* |
336 | * Start hpet with the boot cpu mask and make it | 377 | * Start hpet with the boot cpu mask and make it |
337 | * global after the IO_APIC has been initialized. | 378 | * global after the IO_APIC has been initialized. |
@@ -349,6 +390,22 @@ out_nohpet: | |||
349 | return 0; | 390 | return 0; |
350 | } | 391 | } |
351 | 392 | ||
393 | /* | ||
394 | * Needs to be late, as the reserve_timer code calls kalloc ! | ||
395 | * | ||
396 | * Not a problem on i386 as hpet_enable is called from late_time_init, | ||
397 | * but on x86_64 it is necessary ! | ||
398 | */ | ||
399 | static __init int hpet_late_init(void) | ||
400 | { | ||
401 | if (!is_hpet_capable()) | ||
402 | return -ENODEV; | ||
403 | |||
404 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); | ||
405 | return 0; | ||
406 | } | ||
407 | fs_initcall(hpet_late_init); | ||
408 | |||
352 | #ifdef CONFIG_HPET_EMULATE_RTC | 409 | #ifdef CONFIG_HPET_EMULATE_RTC |
353 | 410 | ||
354 | /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET | 411 | /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET |