diff options
author | Andres Salomon <dilinger@debian.org> | 2008-02-09 17:24:08 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-02-09 17:24:08 -0500 |
commit | f54ae69bafa16434ce46bc2f1fe556bce4d23650 (patch) | |
tree | 642ce77688984fc60c1f7d8dc2e7e8ad982c9cf9 /arch/x86/kernel/mfgpt_32.c | |
parent | f087515c658a68454d43909d482ea4b59e7d6d5c (diff) |
x86: GEODE: MFGPT: fix a potential race when disabling a timer
We *really* don't want to be reading MFGPTx_SETUP and writing back those
values. What we want to be doing is clearing CMP1 and CMP2 unconditionally;
otherwise, we have races where CMP1 and/or CMP2 fire after we've read
MFGPTx_SETUP. They can also fire between when we've written ~CNTEN to
the register, and when the new register values get copied to the timer's
version of the register. By clearing both fields, we're okay.
Signed-off-by: Andres Salomon <dilinger@debian.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/mfgpt_32.c')
-rw-r--r-- | arch/x86/kernel/mfgpt_32.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c index abdb7c71199a..81aa9db01f5f 100644 --- a/arch/x86/kernel/mfgpt_32.c +++ b/arch/x86/kernel/mfgpt_32.c | |||
@@ -249,8 +249,9 @@ __setup("mfgpt_irq=", mfgpt_setup); | |||
249 | 249 | ||
250 | static void mfgpt_disable_timer(u16 clock) | 250 | static void mfgpt_disable_timer(u16 clock) |
251 | { | 251 | { |
252 | u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP); | 252 | /* avoid races by clearing CMP1 and CMP2 unconditionally */ |
253 | geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN); | 253 | geode_mfgpt_write(clock, MFGPT_REG_SETUP, (u16) ~MFGPT_SETUP_CNTEN | |
254 | MFGPT_SETUP_CMP1 | MFGPT_SETUP_CMP2); | ||
254 | } | 255 | } |
255 | 256 | ||
256 | static int mfgpt_next_event(unsigned long, struct clock_event_device *); | 257 | static int mfgpt_next_event(unsigned long, struct clock_event_device *); |