diff options
Diffstat (limited to 'arch/x86/kernel/i8253.c')
-rw-r--r-- | arch/x86/kernel/i8253.c | 72 |
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 | ||
17 | DEFINE_SPINLOCK(i8253_lock); | 18 | DEFINE_SPINLOCK(i8253_lock); |
18 | EXPORT_SYMBOL(i8253_lock); | 19 | EXPORT_SYMBOL(i8253_lock); |
19 | 20 | ||
21 | #ifdef CONFIG_X86_32 | ||
22 | static void pit_disable_clocksource(void); | ||
23 | #else | ||
24 | static 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; | |||
31 | static void init_pit_timer(enum clock_event_mode mode, | 38 | static 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 | */ |
73 | static int pit_next_event(unsigned long delta, struct clock_event_device *evt) | 80 | static 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 | ||
203 | static 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 | |||
198 | static int __init init_pit_clocksource(void) | 214 | static 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); |