On Fri, Oct 26, 2007 at 08:18:35AM +0200, Manuel Lauss wrote: > On Thu, Oct 25, 2007 at 06:59:14PM +0100, Ralf Baechle wrote: > > On Wed, Oct 24, 2007 at 08:31:35PM +0200, Manuel Lauss wrote: > > > start_kernel() > > > time_init() > > > init_mips_clocksource() > > > mips_clockevent_init() > > > clockevents_register_device() > > > clockevents_do_notify() > > > notifier_call_chain(): > > > > > > It dies here, line 69, in kernel/notifier.c: > > > ret = nb->notifier_call(nb, val, v); > > > tick_notify(&tick_notifier, CLOCK_EVT_NOTIFY_ADD, dev) > > > > So things are likely going wrong somewhere in there. > > starting in nb->notifier_call: > tick_notify() > tick_check_new_device() > tick_setup_device() > tick_setup_periodic(): > > it seems to enternally loop in here: > > 123 for (;;) { > 124 if (!clockevents_program_event(dev, next, ktime_get())) > 125 return; > 126 next = ktime_add(next, tick_period); > 127 } > > I think it's waiting for a timer irq which never happens. The code in > cevt-r4k.c assigns IRQ 7 as the timer irq which is a GPIO according to > the manual. Actually, there is no real requestable() timer irq mentioned > in the manual (RTC and TOY aside). As I said before, I've renumbered interrupts on Alchemy. 0 ... 7 are now the processor's built-in interrupt controller (see the IE bits in the CPU status and cause register). The Alchemy SOC's interrupt controller has moved to interrupts 8 ... 71. So what must be happening is that clockevents_program_event is returning a non-zero value, that's the only thing that can make above loop going forever. Now looking at clockevents_program_event: int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, ktime_t now) { unsigned long long clc; int64_t delta; delta = ktime_to_ns(ktime_sub(expires, now)); if (delta <= 0) return -ETIME; dev->next_event = expires; if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN) return 0; if (delta > dev->max_delta_ns) delta = dev->max_delta_ns; if (delta < dev->min_delta_ns) delta = dev->min_delta_ns; clc = delta * dev->mult; clc >>= dev->shift; return dev->set_next_event((unsigned long) clc, dev); } So you either must be hitting the "delta <= 0" check. Or ->set_next_event is returning an error. So as your earlier calltrace of the hang shows you are using cevt-r4k.c for the clockevent device so the function getting called would be arch/mips/kernel/cevt-r4k.c:mips_next_event(). With the #ifdefery removed this function looks like this: static int mips_next_event(unsigned long delta, struct clock_event_device *evt) { unsigned int cnt; int res; cnt = read_c0_count(); cnt += delta; write_c0_compare(cnt); res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; return res; } So this would return an error if by the time the compare register has been programmed the timer has already expired which would happen for exmaple if it was programmed for an extremly short time into the future. The timer clock initialization code in cevt-r4k.c: /* Calculate the min / max delta */ cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); cd->shift = 32; cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); cd->min_delta_ns = clockevent_delta2ns(0x300, cd); Looks a little oldfashioned but okay otherwise - if mips_freq is sane. So let's see. mips_freq is initialized from mips_hpt_frequency which the platform code should have initialized in plat_time_init() which happens in arch/mips/au1000/common/time.c: cal_r4koff() which is getting called from plat_timer_setup which is called from ... nowhere anymore whoops. I could restore the call easily but that function is on the way out and any user of plat_timer_setup has likely other bugs in the new time code. Can you try below patch? Ralf Signed-off-by: Ralf Baechle <ralf@xxxxxxxxxxxxxx> arch/mips/au1000/common/time.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 0673fc0..f113b51 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -228,7 +228,7 @@ unsigned long cal_r4koff(void) return (cpu_speed / HZ); } -void __init plat_timer_setup(struct irqaction *irq) +void __init plat_time_init(void) { unsigned int est_freq;