aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/i8253.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/i8253.c')
-rw-r--r--arch/x86/kernel/i8253.c72
1 files changed, 48 insertions, 24 deletions
diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c
index a42c80745325..ef62b07b2b48 100644
--- a/arch/x86/kernel/i8253.c
+++ b/arch/x86/kernel/i8253.c
@@ -13,10 +13,17 @@
13#include <asm/delay.h> 13#include <asm/delay.h>
14#include <asm/i8253.h> 14#include <asm/i8253.h>
15#include <asm/io.h> 15#include <asm/io.h>
16#include <asm/hpet.h>
16 17
17DEFINE_SPINLOCK(i8253_lock); 18DEFINE_SPINLOCK(i8253_lock);
18EXPORT_SYMBOL(i8253_lock); 19EXPORT_SYMBOL(i8253_lock);
19 20
21#ifdef CONFIG_X86_32
22static void pit_disable_clocksource(void);
23#else
24static inline void pit_disable_clocksource(void) { }
25#endif
26
20/* 27/*
21 * HPET replaces the PIT, when enabled. So we need to know, which of 28 * HPET replaces the PIT, when enabled. So we need to know, which of
22 * the two timers is used 29 * the two timers is used
@@ -31,38 +38,38 @@ struct clock_event_device *global_clock_event;
31static void init_pit_timer(enum clock_event_mode mode, 38static void init_pit_timer(enum clock_event_mode mode,
32 struct clock_event_device *evt) 39 struct clock_event_device *evt)
33{ 40{
34 unsigned long flags; 41 spin_lock(&i8253_lock);
35
36 spin_lock_irqsave(&i8253_lock, flags);
37 42
38 switch(mode) { 43 switch(mode) {
39 case CLOCK_EVT_MODE_PERIODIC: 44 case CLOCK_EVT_MODE_PERIODIC:
40 /* binary, mode 2, LSB/MSB, ch 0 */ 45 /* binary, mode 2, LSB/MSB, ch 0 */
41 outb_p(0x34, PIT_MODE); 46 outb_pit(0x34, PIT_MODE);
42 outb_p(LATCH & 0xff , PIT_CH0); /* LSB */ 47 outb_pit(LATCH & 0xff , PIT_CH0); /* LSB */
43 outb(LATCH >> 8 , PIT_CH0); /* MSB */ 48 outb_pit(LATCH >> 8 , PIT_CH0); /* MSB */
44 break; 49 break;
45 50
46 case CLOCK_EVT_MODE_SHUTDOWN: 51 case CLOCK_EVT_MODE_SHUTDOWN:
47 case CLOCK_EVT_MODE_UNUSED: 52 case CLOCK_EVT_MODE_UNUSED:
48 if (evt->mode == CLOCK_EVT_MODE_PERIODIC || 53 if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
49 evt->mode == CLOCK_EVT_MODE_ONESHOT) { 54 evt->mode == CLOCK_EVT_MODE_ONESHOT) {
50 outb_p(0x30, PIT_MODE); 55 outb_pit(0x30, PIT_MODE);
51 outb_p(0, PIT_CH0); 56 outb_pit(0, PIT_CH0);
52 outb_p(0, PIT_CH0); 57 outb_pit(0, PIT_CH0);
53 } 58 }
59 pit_disable_clocksource();
54 break; 60 break;
55 61
56 case CLOCK_EVT_MODE_ONESHOT: 62 case CLOCK_EVT_MODE_ONESHOT:
57 /* One shot setup */ 63 /* One shot setup */
58 outb_p(0x38, PIT_MODE); 64 pit_disable_clocksource();
65 outb_pit(0x38, PIT_MODE);
59 break; 66 break;
60 67
61 case CLOCK_EVT_MODE_RESUME: 68 case CLOCK_EVT_MODE_RESUME:
62 /* Nothing to do here */ 69 /* Nothing to do here */
63 break; 70 break;
64 } 71 }
65 spin_unlock_irqrestore(&i8253_lock, flags); 72 spin_unlock(&i8253_lock);
66} 73}
67 74
68/* 75/*
@@ -72,12 +79,10 @@ static void init_pit_timer(enum clock_event_mode mode,
72 */ 79 */
73static int pit_next_event(unsigned long delta, struct clock_event_device *evt) 80static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
74{ 81{
75 unsigned long flags; 82 spin_lock(&i8253_lock);
76 83 outb_pit(delta & 0xff , PIT_CH0); /* LSB */
77 spin_lock_irqsave(&i8253_lock, flags); 84 outb_pit(delta >> 8 , PIT_CH0); /* MSB */
78 outb_p(delta & 0xff , PIT_CH0); /* LSB */ 85 spin_unlock(&i8253_lock);
79 outb(delta >> 8 , PIT_CH0); /* MSB */
80 spin_unlock_irqrestore(&i8253_lock, flags);
81 86
82 return 0; 87 return 0;
83} 88}
@@ -148,15 +153,15 @@ static cycle_t pit_read(void)
148 * count), it cannot be newer. 153 * count), it cannot be newer.
149 */ 154 */
150 jifs = jiffies; 155 jifs = jiffies;
151 outb_p(0x00, PIT_MODE); /* latch the count ASAP */ 156 outb_pit(0x00, PIT_MODE); /* latch the count ASAP */
152 count = inb_p(PIT_CH0); /* read the latched count */ 157 count = inb_pit(PIT_CH0); /* read the latched count */
153 count |= inb_p(PIT_CH0) << 8; 158 count |= inb_pit(PIT_CH0) << 8;
154 159
155 /* VIA686a test code... reset the latch if count > max + 1 */ 160 /* VIA686a test code... reset the latch if count > max + 1 */
156 if (count > LATCH) { 161 if (count > LATCH) {
157 outb_p(0x34, PIT_MODE); 162 outb_pit(0x34, PIT_MODE);
158 outb_p(LATCH & 0xff, PIT_CH0); 163 outb_pit(LATCH & 0xff, PIT_CH0);
159 outb(LATCH >> 8, PIT_CH0); 164 outb_pit(LATCH >> 8, PIT_CH0);
160 count = LATCH - 1; 165 count = LATCH - 1;
161 } 166 }
162 167
@@ -195,9 +200,28 @@ static struct clocksource clocksource_pit = {
195 .shift = 20, 200 .shift = 20,
196}; 201};
197 202
203static void pit_disable_clocksource(void)
204{
205 /*
206 * Use mult to check whether it is registered or not
207 */
208 if (clocksource_pit.mult) {
209 clocksource_unregister(&clocksource_pit);
210 clocksource_pit.mult = 0;
211 }
212}
213
198static int __init init_pit_clocksource(void) 214static int __init init_pit_clocksource(void)
199{ 215{
200 if (num_possible_cpus() > 1) /* PIT does not scale! */ 216 /*
217 * Several reasons not to register PIT as a clocksource:
218 *
219 * - On SMP PIT does not scale due to i8253_lock
220 * - when HPET is enabled
221 * - when local APIC timer is active (PIT is switched off)
222 */
223 if (num_possible_cpus() > 1 || is_hpet_enabled() ||
224 pit_clockevent.mode != CLOCK_EVT_MODE_PERIODIC)
201 return 0; 225 return 0;
202 226
203 clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); 227 clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);