[PATCH 0/40] Complete set of clocksource/sched_clock patches
Mikael Pettersson
mikpe at it.uu.se
Sun Dec 19 09:05:56 EST 2010
Russell King - ARM Linux writes:
> > We take an early timer interrupt and call NULL in the
> >
> > evt->event_handler(evt);
> >
> > statement in iop_timer_interrupt(). Apparently the evt (dev_id) passed
> > to the interrupt handler isn't initialized at this point.
>
> evt is initialized, it's done statically:
>
> static struct irqaction iop_timer_irq = {
> .dev_id = &iop_clockevent,
> };
>
> What isn't initialized at this early point is evt->event_handler.
>
> > The most visible change the sched_clock patches did in plat-iop was to add
> > a call to init_sched_clock() at the very start of iop_init_time(), before
> > the timer IRQ, clockevent, and clocksource have been set up. Moving that call
> > to the very end of iop_init_time() [see below] made the kernel boot again,
> > and the interactivity problems were also solved.
>
> I think this is a bug just waiting to happen, and the sched_clock patch
> just gives it a helping hand (by accidentally enabling interrupts early
> - and that's something which also needs fixing.)
>
> Here's the event device setup code:
>
> write_tmr0(timer_ctl & ~IOP_TMR_EN);
> setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
> clockevents_calc_mult_shift(&iop_clockevent,
> tick_rate, IOP_MIN_RANGE);
> iop_clockevent.max_delta_ns =
> clockevent_delta2ns(0xfffffffe, &iop_clockevent);
> iop_clockevent.min_delta_ns =
> clockevent_delta2ns(0xf, &iop_clockevent);
> iop_clockevent.cpumask = cpumask_of(0);
> clockevents_register_device(&iop_clockevent);
> write_trr0(ticks_per_jiffy - 1);
> write_tcr0(ticks_per_jiffy - 1);
> write_tmr0(timer_ctl);
>
> First thing is that although the timer is stopped before the IRQ is
> registered, there is no clearing of any pending timer interrupt at that
> time. As we don't know what state the timer was in, we can't be sure
> that the interrupt isn't already pending.
>
> Second thing is why is the timer being enabled by this code after it's
> been registered. This is something which should be done by the
> clockevents code when it's ready via the ->set_mode callback, not when
> the platform decides to do so - otherwise you can call the interrupt
> handler when evt->event_handler has not been setup.
When I did the IOP clockevents conversion I didn't know that the
timer should be disabled, so I probably just kept the previous code
to enable it.
> So, I think this will solve the IOP misbehaviour. What I don't know
> is what the cryptic txx0() suffixes on these write statements are
> (what's the difference between trr and tcr? tcr = timer counter
> register, trr = timer ? register?
tmr = timer mode register
tcr = timer counter register
trr = timer reload register
When a timer is in periodic mode it reloads itself from its reload
register when the counter register decrements to zero.
> Does trr need to be written in
> ->set_mode (if so that's another bug in this code)?
trr{0,1} need not and should not be changed after iop_time_init().
> diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
> index 0ca000d..e937e5d 100644
> --- a/arch/arm/plat-iop/time.c
> +++ b/arch/arm/plat-iop/time.c
> @@ -162,6 +162,7 @@ void __init iop_init_time(unsigned long tick_rate)
> * Set up interrupting clockevent timer 0.
> */
> write_tmr0(timer_ctl & ~IOP_TMR_EN);
> + write_tisr(1);
> setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
> clockevents_calc_mult_shift(&iop_clockevent,
> tick_rate, IOP_MIN_RANGE);
> @@ -171,9 +172,6 @@ void __init iop_init_time(unsigned long tick_rate)
> clockevent_delta2ns(0xf, &iop_clockevent);
> iop_clockevent.cpumask = cpumask_of(0);
> clockevents_register_device(&iop_clockevent);
> - write_trr0(ticks_per_jiffy - 1);
> - write_tcr0(ticks_per_jiffy - 1);
> - write_tmr0(timer_ctl);
>
> /*
> * Set up free-running clocksource timer 1.
Yes, this seems correct. Tested in a vanilla kernel w/o sched_clock patches,
and in a kernel with the sched_clock patches it eliminated the boot hang.
More information about the linux-arm-kernel
mailing list