Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: GEODE fix a race condition in the MFGPT timer tick

When we set the MFGPT timer tick, there is a chance that we'll
immediately assert an event. If for some reason the IRQ routing
for this clock has been setup for some other purpose, then we
could end up firing an interrupt into the SMM handler or worse.

This rearranges the timer tick init function to initalize the handler
before we set up the MFGPT clock to make sure that even if we get
an event, it will go to the handler.

Furthermore, in the handler we need to make sure that we clear the
event, even if the timer isn't running.

Signed-off-by: Jordan Crouse <jordan.crouse@amd.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Ingo Molnar <mingo@elte.hu>
Tested-by: Arnd Hannemann <hannemann@i4.informatik.rwth-aachen.de>

authored by

Jordan Crouse and committed by
Ingo Molnar
667984d9 889c94a1

+8 -7
+8 -7
arch/x86/kernel/mfgpt_32.c
··· 278 278 279 279 static irqreturn_t mfgpt_tick(int irq, void *dev_id) 280 280 { 281 + /* Turn off the clock (and clear the event) */ 282 + mfgpt_disable_timer(mfgpt_event_clock); 283 + 281 284 if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) 282 285 return IRQ_HANDLED; 283 - 284 - /* Turn off the clock */ 285 - mfgpt_disable_timer(mfgpt_event_clock); 286 286 287 287 /* Clear the counter */ 288 288 geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); ··· 319 319 } 320 320 321 321 mfgpt_event_clock = timer; 322 - /* Set the clock scale and enable the event mode for CMP2 */ 323 - val = MFGPT_SCALE | (3 << 8); 324 - 325 - geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val); 326 322 327 323 /* Set up the IRQ on the MFGPT side */ 328 324 if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) { ··· 334 338 "mfgpt-timer: Unable to set up the interrupt.\n"); 335 339 goto err; 336 340 } 341 + 342 + /* Set the clock scale and enable the event mode for CMP2 */ 343 + val = MFGPT_SCALE | (3 << 8); 344 + 345 + geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val); 337 346 338 347 /* Set up the clock event */ 339 348 mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);