aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/hpet.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/hpet.c')
-rw-r--r--arch/x86_64/kernel/hpet.c109
1 files changed, 44 insertions, 65 deletions
diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet.c
index 65a0edd71a17..8cf0b8a13778 100644
--- a/arch/x86_64/kernel/hpet.c
+++ b/arch/x86_64/kernel/hpet.c
@@ -12,6 +12,12 @@
12#include <asm/timex.h> 12#include <asm/timex.h>
13#include <asm/hpet.h> 13#include <asm/hpet.h>
14 14
15#define HPET_MASK 0xFFFFFFFF
16#define HPET_SHIFT 22
17
18/* FSEC = 10^-15 NSEC = 10^-9 */
19#define FSEC_PER_NSEC 1000000
20
15int nohpet __initdata; 21int nohpet __initdata;
16 22
17unsigned long hpet_address; 23unsigned long hpet_address;
@@ -106,9 +112,31 @@ int hpet_timer_stop_set_go(unsigned long tick)
106 return 0; 112 return 0;
107} 113}
108 114
115static cycle_t read_hpet(void)
116{
117 return (cycle_t)hpet_readl(HPET_COUNTER);
118}
119
120static cycle_t __vsyscall_fn vread_hpet(void)
121{
122 return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
123}
124
125struct clocksource clocksource_hpet = {
126 .name = "hpet",
127 .rating = 250,
128 .read = read_hpet,
129 .mask = (cycle_t)HPET_MASK,
130 .mult = 0, /* set below */
131 .shift = HPET_SHIFT,
132 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
133 .vread = vread_hpet,
134};
135
109int hpet_arch_init(void) 136int hpet_arch_init(void)
110{ 137{
111 unsigned int id; 138 unsigned int id;
139 u64 tmp;
112 140
113 if (!hpet_address) 141 if (!hpet_address)
114 return -1; 142 return -1;
@@ -132,6 +160,22 @@ int hpet_arch_init(void)
132 160
133 hpet_use_timer = (id & HPET_ID_LEGSUP); 161 hpet_use_timer = (id & HPET_ID_LEGSUP);
134 162
163 /*
164 * hpet period is in femto seconds per cycle
165 * so we need to convert this to ns/cyc units
166 * aproximated by mult/2^shift
167 *
168 * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
169 * fsec/cyc * 1ns/1000000fsec * 2^shift = mult
170 * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
171 * (fsec/cyc << shift)/1000000 = mult
172 * (hpet_period << shift)/FSEC_PER_NSEC = mult
173 */
174 tmp = (u64)hpet_period << HPET_SHIFT;
175 do_div(tmp, FSEC_PER_NSEC);
176 clocksource_hpet.mult = (u32)tmp;
177 clocksource_register(&clocksource_hpet);
178
135 return hpet_timer_stop_set_go(hpet_tick); 179 return hpet_timer_stop_set_go(hpet_tick);
136} 180}
137 181
@@ -444,68 +488,3 @@ static int __init nohpet_setup(char *s)
444} 488}
445 489
446__setup("nohpet", nohpet_setup); 490__setup("nohpet", nohpet_setup);
447
448#define HPET_MASK 0xFFFFFFFF
449#define HPET_SHIFT 22
450
451/* FSEC = 10^-15 NSEC = 10^-9 */
452#define FSEC_PER_NSEC 1000000
453
454static void *hpet_ptr;
455
456static cycle_t read_hpet(void)
457{
458 return (cycle_t)readl(hpet_ptr);
459}
460
461static cycle_t __vsyscall_fn vread_hpet(void)
462{
463 return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
464}
465
466struct clocksource clocksource_hpet = {
467 .name = "hpet",
468 .rating = 250,
469 .read = read_hpet,
470 .mask = (cycle_t)HPET_MASK,
471 .mult = 0, /* set below */
472 .shift = HPET_SHIFT,
473 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
474 .vread = vread_hpet,
475};
476
477static int __init init_hpet_clocksource(void)
478{
479 unsigned long hpet_period;
480 void __iomem *hpet_base;
481 u64 tmp;
482
483 if (!hpet_address)
484 return -ENODEV;
485
486 /* calculate the hpet address: */
487 hpet_base = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
488 hpet_ptr = hpet_base + HPET_COUNTER;
489
490 /* calculate the frequency: */
491 hpet_period = readl(hpet_base + HPET_PERIOD);
492
493 /*
494 * hpet period is in femto seconds per cycle
495 * so we need to convert this to ns/cyc units
496 * aproximated by mult/2^shift
497 *
498 * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
499 * fsec/cyc * 1ns/1000000fsec * 2^shift = mult
500 * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
501 * (fsec/cyc << shift)/1000000 = mult
502 * (hpet_period << shift)/FSEC_PER_NSEC = mult
503 */
504 tmp = (u64)hpet_period << HPET_SHIFT;
505 do_div(tmp, FSEC_PER_NSEC);
506 clocksource_hpet.mult = (u32)tmp;
507
508 return clocksource_register(&clocksource_hpet);
509}
510
511module_init(init_hpet_clocksource);