aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2005-05-01 11:58:50 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-01 11:58:50 -0400
commit35492df5ae0f36f717448b2aea908d3a8891d1c4 (patch)
tree4b9ebb20ec019daf301eef37fd6c7b75a7ea7de9 /arch/i386/kernel
parent5b7abc6fdcaf103f15e06c518ef0aec02a9c00e7 (diff)
[PATCH] i386: fix hpet for systems that don't support legacy replacement
Currently the i386 HPET code assumes the entire HPET implementation from the spec is present. This breaks on boxes that do not implement the optional legacy timer replacement functionality portion of the spec. This patch, which is very similar to my x86-64 patch for the same issue, fixes the problem allowing i386 systems that cannot use the HPET for the timer interrupt and RTC to still use the HPET as a time source. I've tested this patch on a system systems without HPET, with HPET but without legacy timer replacement, as well as HPET with legacy timer replacement. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/time.c2
-rw-r--r--arch/i386/kernel/time_hpet.c48
-rw-r--r--arch/i386/kernel/timers/timer_hpet.c11
-rw-r--r--arch/i386/kernel/timers/timer_tsc.c2
4 files changed, 36 insertions, 27 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 4d75b373f90..a0dcb7c87c3 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -441,7 +441,7 @@ static void __init hpet_time_init(void)
441 set_normalized_timespec(&wall_to_monotonic, 441 set_normalized_timespec(&wall_to_monotonic,
442 -xtime.tv_sec, -xtime.tv_nsec); 442 -xtime.tv_sec, -xtime.tv_nsec);
443 443
444 if (hpet_enable() >= 0) { 444 if ((hpet_enable() >= 0) && hpet_use_timer) {
445 printk("Using HPET for base-timer\n"); 445 printk("Using HPET for base-timer\n");
446 } 446 }
447 447
diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c
index 244a31b04be..10a0cbb88e7 100644
--- a/arch/i386/kernel/time_hpet.c
+++ b/arch/i386/kernel/time_hpet.c
@@ -26,6 +26,7 @@
26static unsigned long hpet_period; /* fsecs / HPET clock */ 26static unsigned long hpet_period; /* fsecs / HPET clock */
27unsigned long hpet_tick; /* hpet clks count per tick */ 27unsigned long hpet_tick; /* hpet clks count per tick */
28unsigned long hpet_address; /* hpet memory map physical address */ 28unsigned long hpet_address; /* hpet memory map physical address */
29int hpet_use_timer;
29 30
30static int use_hpet; /* can be used for runtime check of hpet */ 31static int use_hpet; /* can be used for runtime check of hpet */
31static int boot_hpet_disable; /* boottime override for HPET timer */ 32static int boot_hpet_disable; /* boottime override for HPET timer */
@@ -73,27 +74,30 @@ static int hpet_timer_stop_set_go(unsigned long tick)
73 hpet_writel(0, HPET_COUNTER); 74 hpet_writel(0, HPET_COUNTER);
74 hpet_writel(0, HPET_COUNTER + 4); 75 hpet_writel(0, HPET_COUNTER + 4);
75 76
76 /* 77 if (hpet_use_timer) {
77 * Set up timer 0, as periodic with first interrupt to happen at 78 /*
78 * hpet_tick, and period also hpet_tick. 79 * Set up timer 0, as periodic with first interrupt to happen at
79 */ 80 * hpet_tick, and period also hpet_tick.
80 cfg = hpet_readl(HPET_T0_CFG); 81 */
81 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 82 cfg = hpet_readl(HPET_T0_CFG);
82 HPET_TN_SETVAL | HPET_TN_32BIT; 83 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
83 hpet_writel(cfg, HPET_T0_CFG); 84 HPET_TN_SETVAL | HPET_TN_32BIT;
84 85 hpet_writel(cfg, HPET_T0_CFG);
85 /*
86 * The first write after writing TN_SETVAL to the config register sets
87 * the counter value, the second write sets the threshold.
88 */
89 hpet_writel(tick, HPET_T0_CMP);
90 hpet_writel(tick, HPET_T0_CMP);
91 86
87 /*
88 * The first write after writing TN_SETVAL to the config register sets
89 * the counter value, the second write sets the threshold.
90 */
91 hpet_writel(tick, HPET_T0_CMP);
92 hpet_writel(tick, HPET_T0_CMP);
93 }
92 /* 94 /*
93 * Go! 95 * Go!
94 */ 96 */
95 cfg = hpet_readl(HPET_CFG); 97 cfg = hpet_readl(HPET_CFG);
96 cfg |= HPET_CFG_ENABLE | HPET_CFG_LEGACY; 98 if (hpet_use_timer)
99 cfg |= HPET_CFG_LEGACY;
100 cfg |= HPET_CFG_ENABLE;
97 hpet_writel(cfg, HPET_CFG); 101 hpet_writel(cfg, HPET_CFG);
98 102
99 return 0; 103 return 0;
@@ -128,12 +132,11 @@ int __init hpet_enable(void)
128 * However, we can do with one timer otherwise using the 132 * However, we can do with one timer otherwise using the
129 * the single HPET timer for system time. 133 * the single HPET timer for system time.
130 */ 134 */
131 if (
132#ifdef CONFIG_HPET_EMULATE_RTC 135#ifdef CONFIG_HPET_EMULATE_RTC
133 !(id & HPET_ID_NUMBER) || 136 if (!(id & HPET_ID_NUMBER))
134#endif
135 !(id & HPET_ID_LEGSUP))
136 return -1; 137 return -1;
138#endif
139
137 140
138 hpet_period = hpet_readl(HPET_PERIOD); 141 hpet_period = hpet_readl(HPET_PERIOD);
139 if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD)) 142 if ((hpet_period < HPET_MIN_PERIOD) || (hpet_period > HPET_MAX_PERIOD))
@@ -152,6 +155,8 @@ int __init hpet_enable(void)
152 if (hpet_tick_rem > (hpet_period >> 1)) 155 if (hpet_tick_rem > (hpet_period >> 1))
153 hpet_tick++; /* rounding the result */ 156 hpet_tick++; /* rounding the result */
154 157
158 hpet_use_timer = id & HPET_ID_LEGSUP;
159
155 if (hpet_timer_stop_set_go(hpet_tick)) 160 if (hpet_timer_stop_set_go(hpet_tick))
156 return -1; 161 return -1;
157 162
@@ -202,7 +207,8 @@ int __init hpet_enable(void)
202#endif 207#endif
203 208
204#ifdef CONFIG_X86_LOCAL_APIC 209#ifdef CONFIG_X86_LOCAL_APIC
205 wait_timer_tick = wait_hpet_tick; 210 if (hpet_use_timer)
211 wait_timer_tick = wait_hpet_tick;
206#endif 212#endif
207 return 0; 213 return 0;
208} 214}
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
index 713134e7184..f778f471a09 100644
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ b/arch/i386/kernel/timers/timer_hpet.c
@@ -79,7 +79,7 @@ static unsigned long get_offset_hpet(void)
79 79
80 eax = hpet_readl(HPET_COUNTER); 80 eax = hpet_readl(HPET_COUNTER);
81 eax -= hpet_last; /* hpet delta */ 81 eax -= hpet_last; /* hpet delta */
82 82 eax = min(hpet_tick, eax);
83 /* 83 /*
84 * Time offset = (hpet delta) * ( usecs per HPET clock ) 84 * Time offset = (hpet delta) * ( usecs per HPET clock )
85 * = (hpet delta) * ( usecs per tick / HPET clocks per tick) 85 * = (hpet delta) * ( usecs per tick / HPET clocks per tick)
@@ -105,9 +105,12 @@ static void mark_offset_hpet(void)
105 last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; 105 last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
106 rdtsc(last_tsc_low, last_tsc_high); 106 rdtsc(last_tsc_low, last_tsc_high);
107 107
108 offset = hpet_readl(HPET_T0_CMP) - hpet_tick; 108 if (hpet_use_timer)
109 if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0))) { 109 offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
110 int lost_ticks = (offset - hpet_last) / hpet_tick; 110 else
111 offset = hpet_readl(HPET_COUNTER);
112 if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) {
113 int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1;
111 jiffies_64 += lost_ticks; 114 jiffies_64 += lost_ticks;
112 } 115 }
113 hpet_last = offset; 116 hpet_last = offset;
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
index a685994e5c8..7926d967be0 100644
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ b/arch/i386/kernel/timers/timer_tsc.c
@@ -477,7 +477,7 @@ static int __init init_tsc(char* override)
477 if (cpu_has_tsc) { 477 if (cpu_has_tsc) {
478 unsigned long tsc_quotient; 478 unsigned long tsc_quotient;
479#ifdef CONFIG_HPET_TIMER 479#ifdef CONFIG_HPET_TIMER
480 if (is_hpet_enabled()){ 480 if (is_hpet_enabled() && hpet_use_timer) {
481 unsigned long result, remain; 481 unsigned long result, remain;
482 printk("Using TSC for gettimeofday\n"); 482 printk("Using TSC for gettimeofday\n");
483 tsc_quotient = calibrate_tsc_hpet(NULL); 483 tsc_quotient = calibrate_tsc_hpet(NULL);