Re: 2.6.24-rc8 hangs at mfgpt-timer

From: Jordan Crouse
Date: Tue Jan 22 2008 - 14:27:34 EST


> Indeed.
> Strange, it works at least with mfgpt_irq=8 (rtc) and mfgpt_irq=5 (audio):

I have most excellent news. I was able to get tinyBIOS booting on my
development platform. I looked at the problem with the debugger and
I think I might have found something. It looks like the interrupt is
firing immediately before the clock is enabled. In the handler, we
were returning immediately if the clock wasn't enabled (and not clearing
the event), so we were caught in a classic interrupt storm.

The attached patch rearranges the code so that the handler is installed
before we setup the interrupt (so we have somebody to listen to the
immediate interrupt), and it makes sure that we clear the event in the IRQ
handler regardless of the state of the timer tick.

I'm not 100% sure why this happens on IRQ7 but not on 5 or 8, but it might
have something to do with the interrupts already being enabled on the other
vectors. Anyway, please try this test patch and let me know what happens.

Jordan

--
Jordan Crouse
Systems Software Development Engineer
Advanced Micro Devices, Inc.
[GEODE] fix a race condition in the MFGPT timer tick

From: Jordan Crouse <jordan.crouse@xxxxxxx>

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@xxxxxxx>
---

arch/x86/kernel/mfgpt_32.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)

Index: git/arch/x86/kernel/mfgpt_32.c
===================================================================
--- git.orig/arch/x86/kernel/mfgpt_32.c 2008-01-21 17:09:54.000000000 -0700
+++ git/arch/x86/kernel/mfgpt_32.c 2008-01-22 12:21:21.000000000 -0700
@@ -278,12 +278,12 @@

static irqreturn_t mfgpt_tick(int irq, void *dev_id)
{
+ /* Turn off the clock (and clear the event) */
+ mfgpt_disable_timer(mfgpt_event_clock);
+
if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
return IRQ_HANDLED;

- /* Turn off the clock */
- mfgpt_disable_timer(mfgpt_event_clock);
-
/* Clear the counter */
geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);

@@ -319,10 +319,6 @@
}

mfgpt_event_clock = timer;
- /* Set the clock scale and enable the event mode for CMP2 */
- val = MFGPT_SCALE | (3 << 8);
-
- geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);

/* Set up the IRQ on the MFGPT side */
if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
@@ -339,6 +335,11 @@
goto err;
}

+ /* Set the clock scale and enable the event mode for CMP2 */
+ val = MFGPT_SCALE | (3 << 8);
+
+ geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
+
/* Set up the clock event */
mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,