On Thu, Sep 18, 2003 at 04:20:10PM +0100, Georg Nikodym wrote:
> Investigation led us to look at the occasionally discussed loop in
> pxa_timer_interrupt() (pretty much the same as the one used on SA1100):
Funny, we just got a theory that involves that very same
loop in the ixp425 tree.
> static void pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
> {
> long flags;
> int next_match;
>
> do_profile(regs);
I don't have the pxa patch at hand; I assume that
do_profile() acknowledges the interrupt?
I am unsure how the PXA timers work, so I'll develop on the
IXP425 timer loop (I think it is essentially the same):
static void ixp425_timer_interrupt
(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
/* Clear Pending Interrupt by writing '1' to it */
*IXP425_OSST = IXP425_OSST_TIMER_1_PEND;
/*
* Catch up with the real idea of time
* (but only if last_jiffy_time isn't going to go
* beyong OSTS)
*/
do {
local_irq_save(flags);
do_timer(regs);
last_jiffy_time += LATCH;
local_irq_restore(flags);
} while((*IXP425_OSTS - last_jiffy_time) > LATCH)
}
For context, OSTS is a free-running timer which is used as a
time reference, while another timer produces the actual
interrupt.
There is jitter in the system (otherwise the loop would be
useless); the interesting case is when a timer interrupt has
been postponed by exactly one LATCH. Suppose it happens
*after* the interrupt was acknowledge, *before* the end of
the loop. The interrupt register has been cleared, so the
interrupt is recorded; meanwhile, we are in the loop
catching up the last interrupt; as OSTS confirms we have
lost one interrupt (which is in fact the one recorded in
OSST), we also treat that one.
On leaving the loop, we become able to treat that new
interrupt; because of the structure of the loop (
do{ ... }while), we always do at least one iteration.
Effectively, that means that if an interrupt happens while a
timer interrupt is already in treatment, it will be counted
twice. The problem here is that it pushes last_jiffy_time
*beyond* OSTS, and the loop immediately deduces that we lost
a bunch of interrupts (2^32/LATCH), and proceeds to catch up
for equivalent of a revolution of OSTS: we see the clock
jump 65 seconds (32 bit counter counting at 66MHz).
This should be corrected either by:
- Moving the interrupt register clearing after the loop
(effectively masking the timer interrupt until it is
treated)
- Turning the do { } while() into a while(){ }, so the loop
only executes once if it actually needs to.
'should be corrected', as we are still in the process of
testing the fix... Patch coming soon (hopefully).
> 2. Anybody have any other thoughts on why our work-around works?
It adds a little slack that avoids repeating that loop one
time too many?.. not sure about that.
Hope you'll find this is relevant to your problem.
/Y
--
This signature left empty.