lkml.org 
[lkml]   [2007]   [Mar]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [5/6] 2.6.21-rc2: known regressions

    * Linus Torvalds <torvalds@linux-foundation.org> wrote:

    > > Compiling right now - delayed because I just had to pick up one of
    > > the kids from gymnastics.
    >
    > Ok, it does indeed solve the problem for me.
    >
    > Mind sending a signed-off thing with explanations etc?

    here's Thomas' patch with explanations:

    ------------------------->
    From: Thomas Gleixner <tglx@linutronix.de>

    The programming of periodic tick devices needs to be saved/restored
    across suspend/resume - otherwise we might end up with a system coming
    up that relies on getting a PIT (or HPET) interrupt, while those devices
    default to 'no interrupts' after powerup. (To confuse things it worked
    to a certain degree on some systems because the lapic gets initialized
    as a side-effect of SMP bootup.)

    This suspend / resume thing was dropped unintentionally during the
    last-minute -mm code reshuffling.

    Signed-off-by: Ingo Molnar <mingo@elte.hu>

    diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
    index 12b3efe..5567745 100644
    --- a/kernel/time/tick-broadcast.c
    +++ b/kernel/time/tick-broadcast.c
    @@ -284,6 +284,42 @@ void tick_shutdown_broadcast(unsigned int *cpup)
    spin_unlock_irqrestore(&tick_broadcast_lock, flags);
    }

    +void tick_suspend_broadcast(void)
    +{
    + struct clock_event_device *bc;
    + unsigned long flags;
    +
    + spin_lock_irqsave(&tick_broadcast_lock, flags);
    +
    + bc = tick_broadcast_device.evtdev;
    + if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
    + clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
    +
    + spin_unlock_irqrestore(&tick_broadcast_lock, flags);
    +}
    +
    +int tick_resume_broadcast(void)
    +{
    + struct clock_event_device *bc;
    + unsigned long flags;
    + int broadcast = 0;
    +
    + spin_lock_irqsave(&tick_broadcast_lock, flags);
    +
    + bc = tick_broadcast_device.evtdev;
    + if (bc) {
    + if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC &&
    + !cpus_empty(tick_broadcast_mask))
    + tick_broadcast_start_periodic(bc);
    +
    + broadcast = cpu_isset(smp_processor_id(), tick_broadcast_mask);
    + }
    + spin_unlock_irqrestore(&tick_broadcast_lock, flags);
    +
    + return broadcast;
    +}
    +
    +
    #ifdef CONFIG_TICK_ONESHOT

    static cpumask_t tick_broadcast_oneshot_mask;
    diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
    index 0986a2b..43ba1bd 100644
    --- a/kernel/time/tick-common.c
    +++ b/kernel/time/tick-common.c
    @@ -298,6 +298,28 @@ static void tick_shutdown(unsigned int *cpup)
    spin_unlock_irqrestore(&tick_device_lock, flags);
    }

    +static void tick_suspend_periodic(void)
    +{
    + struct tick_device *td = &__get_cpu_var(tick_cpu_device);
    + unsigned long flags;
    +
    + spin_lock_irqsave(&tick_device_lock, flags);
    + if (td->mode == TICKDEV_MODE_PERIODIC)
    + clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_SHUTDOWN);
    + spin_unlock_irqrestore(&tick_device_lock, flags);
    +}
    +
    +static void tick_resume_periodic(void)
    +{
    + struct tick_device *td = &__get_cpu_var(tick_cpu_device);
    + unsigned long flags;
    +
    + spin_lock_irqsave(&tick_device_lock, flags);
    + if (td->mode == TICKDEV_MODE_PERIODIC)
    + tick_setup_periodic(td->evtdev, 0);
    + spin_unlock_irqrestore(&tick_device_lock, flags);
    +}
    +
    /*
    * Notification about clock event devices
    */
    @@ -325,6 +347,16 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
    tick_shutdown(dev);
    break;

    + case CLOCK_EVT_NOTIFY_SUSPEND:
    + tick_suspend_periodic();
    + tick_suspend_broadcast();
    + break;
    +
    + case CLOCK_EVT_NOTIFY_RESUME:
    + if (!tick_resume_broadcast())
    + tick_resume_periodic();
    + break;
    +
    default:
    break;
    }
    diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
    index 54861a0..75890ef 100644
    --- a/kernel/time/tick-internal.h
    +++ b/kernel/time/tick-internal.h
    @@ -67,6 +67,8 @@ extern int tick_check_broadcast_device(struct clock_event_device *dev);
    extern int tick_is_broadcast_device(struct clock_event_device *dev);
    extern void tick_broadcast_on_off(unsigned long reason, int *oncpu);
    extern void tick_shutdown_broadcast(unsigned int *cpup);
    +extern void tick_suspend_broadcast(void);
    +extern int tick_resume_broadcast(void);

    extern void
    tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
    @@ -90,6 +92,8 @@ static inline int tick_device_uses_broadcast(struct clock_event_device *dev,
    static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
    static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { }
    static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
    +static inline void tick_suspend_broadcast(void) { }
    +static inline int tick_resume_broadcast(void) { return 0; }

    /*
    * Set the periodic handler in non broadcast mode
    diff --git a/kernel/timer.c b/kernel/timer.c
    index 6663a87..718437f 100644
    --- a/kernel/timer.c
    +++ b/kernel/timer.c
    @@ -997,6 +997,9 @@ static int timekeeping_resume(struct sys_device *dev)
    write_sequnlock_irqrestore(&xtime_lock, flags);

    touch_softlockup_watchdog();
    +
    + clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
    +
    /* Resume hrtimers */
    clock_was_set();

    @@ -1011,6 +1014,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
    timekeeping_suspended = 1;
    timekeeping_suspend_time = read_persistent_clock();
    write_sequnlock_irqrestore(&xtime_lock, flags);
    +
    + clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
    +
    return 0;
    }

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-03-06 08:31    [W:0.031 / U:29.772 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site