Skip to content

Commit

Permalink
clockevents: fix resume logic
Browse files Browse the repository at this point in the history
We need to make sure, that the clockevent devices are resumed, before
the tick is resumed. The current resume logic does not guarantee this.

Add CLOCK_EVT_MODE_RESUME and call the set mode functions of the clock
event devices before resuming the tick / oneshot functionality.

Fixup the existing users.

Thanks to Nigel Cunningham for tracking down a long standing thinko,
which affected the jinxed VAIO.

[akpm@linux-foundation.org: xen build fix]
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Thomas Gleixner authored and Linus Torvalds committed Jul 22, 2007
1 parent 93da56e commit 18de5bc
Show file tree
Hide file tree
Showing 16 changed files with 51 additions and 88 deletions.
2 changes: 2 additions & 0 deletions arch/arm/mach-davinci/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ static void davinci_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_SHUTDOWN:
t->opts = TIMER_OPTS_DISABLED;
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-imx/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_RESUME:
/* Left event sources disabled, no more interrupts appears */
break;
}
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mach-ixp4xx/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ static void ixp4xx_set_mode(enum clock_event_mode mode,
default:
osrt = opts = 0;
break;
case CLOCK_EVT_MODE_RESUME:
break;
}

*IXP4XX_OSRT1 = osrt | opts;
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-omap1/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ static void omap_mpu_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
break;
}
}
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/plat-omap/timer32k.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ static void omap_32k_timer_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_SHUTDOWN:
omap_32k_timer_stop();
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}

Expand Down
3 changes: 3 additions & 0 deletions arch/i386/kernel/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ static void lapic_timer_setup(enum clock_event_mode mode,
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
apic_write_around(APIC_LVTT, v);
break;
case CLOCK_EVT_MODE_RESUME:
/* Nothing to do here */
break;
}

local_irq_restore(flags);
Expand Down
71 changes: 5 additions & 66 deletions arch/i386/kernel/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ static void hpet_set_mode(enum clock_event_mode mode,
cfg &= ~HPET_TN_ENABLE;
hpet_writel(cfg, HPET_T0_CFG);
break;

case CLOCK_EVT_MODE_RESUME:
hpet_enable_int();
break;
}
}

Expand Down Expand Up @@ -217,6 +221,7 @@ static struct clocksource clocksource_hpet = {
.mask = HPET_MASK,
.shift = HPET_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.resume = hpet_start_counter,
};

/*
Expand Down Expand Up @@ -291,7 +296,6 @@ int __init hpet_enable(void)

clocksource_register(&clocksource_hpet);


if (id & HPET_ID_LEGSUP) {
hpet_enable_int();
hpet_reserve_platform_timers(id);
Expand Down Expand Up @@ -524,68 +528,3 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
#endif


/*
* Suspend/resume part
*/

#ifdef CONFIG_PM

static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
{
unsigned long cfg = hpet_readl(HPET_CFG);

cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
hpet_writel(cfg, HPET_CFG);

return 0;
}

static int hpet_resume(struct sys_device *sys_device)
{
unsigned int id;

hpet_start_counter();

id = hpet_readl(HPET_ID);

if (id & HPET_ID_LEGSUP)
hpet_enable_int();

return 0;
}

static struct sysdev_class hpet_class = {
set_kset_name("hpet"),
.suspend = hpet_suspend,
.resume = hpet_resume,
};

static struct sys_device hpet_device = {
.id = 0,
.cls = &hpet_class,
};


static __init int hpet_register_sysfs(void)
{
int err;

if (!is_hpet_capable())
return 0;

err = sysdev_class_register(&hpet_class);

if (!err) {
err = sysdev_register(&hpet_device);
if (err)
sysdev_class_unregister(&hpet_class);
}

return err;
}

device_initcall(hpet_register_sysfs);

#endif
26 changes: 12 additions & 14 deletions arch/i386/kernel/i8253.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
*
*/
#include <linux/clockchips.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/sysdev.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>

#include <asm/smp.h>
#include <asm/delay.h>
Expand Down Expand Up @@ -41,26 +41,24 @@ static void init_pit_timer(enum clock_event_mode mode,
case CLOCK_EVT_MODE_PERIODIC:
/* binary, mode 2, LSB/MSB, ch 0 */
outb_p(0x34, PIT_MODE);
udelay(10);
outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
udelay(10);
outb(LATCH >> 8 , PIT_CH0); /* MSB */
break;

/*
* Avoid unnecessary state transitions, as it confuses
* Geode / Cyrix based boxen.
*/
case CLOCK_EVT_MODE_SHUTDOWN:
if (evt->mode == CLOCK_EVT_MODE_UNUSED)
break;
case CLOCK_EVT_MODE_UNUSED:
if (evt->mode == CLOCK_EVT_MODE_SHUTDOWN)
break;
outb_p(0x30, PIT_MODE);
outb_p(0, PIT_CH0); /* LSB */
outb_p(0, PIT_CH0); /* MSB */
break;

case CLOCK_EVT_MODE_ONESHOT:
/* One shot setup */
outb_p(0x38, PIT_MODE);
udelay(10);
break;

case CLOCK_EVT_MODE_RESUME:
/* Nothing to do here */
break;
}
spin_unlock_irqrestore(&i8253_lock, flags);
Expand Down
1 change: 1 addition & 0 deletions arch/i386/kernel/vmiclock.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ static void vmi_timer_set_mode(enum clock_event_mode mode,

switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_RESUME:
break;
case CLOCK_EVT_MODE_PERIODIC:
cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
Expand Down
3 changes: 3 additions & 0 deletions arch/i386/xen/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ static void xen_timerop_set_mode(enum clock_event_mode mode,
break;

case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_RESUME:
break;

case CLOCK_EVT_MODE_UNUSED:
Expand Down Expand Up @@ -474,6 +475,8 @@ static void xen_vcpuop_set_mode(enum clock_event_mode mode,
HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
BUG();
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions arch/sh/kernel/timers/timer-tmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ static void tmu_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/sparc64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,7 @@ static void sparc64_timer_setup(enum clock_event_mode mode,
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_RESUME:
break;

case CLOCK_EVT_MODE_SHUTDOWN:
Expand Down
2 changes: 2 additions & 0 deletions drivers/lguest/lguest.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_PERIODIC:
BUG();
case CLOCK_EVT_MODE_RESUME:
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions include/linux/clockchips.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum clock_event_mode {
CLOCK_EVT_MODE_SHUTDOWN,
CLOCK_EVT_MODE_PERIODIC,
CLOCK_EVT_MODE_ONESHOT,
CLOCK_EVT_MODE_RESUME,
};

/* Clock event notification values */
Expand Down
6 changes: 4 additions & 2 deletions kernel/time/tick-broadcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ cpumask_t *tick_get_broadcast_mask(void)
*/
static void tick_broadcast_start_periodic(struct clock_event_device *bc)
{
if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN)
if (bc)
tick_setup_periodic(bc, 1);
}

Expand Down Expand Up @@ -299,7 +299,7 @@ void tick_suspend_broadcast(void)
spin_lock_irqsave(&tick_broadcast_lock, flags);

bc = tick_broadcast_device.evtdev;
if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
if (bc)
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);

spin_unlock_irqrestore(&tick_broadcast_lock, flags);
Expand All @@ -316,6 +316,8 @@ int tick_resume_broadcast(void)
bc = tick_broadcast_device.evtdev;

if (bc) {
clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME);

switch (tick_broadcast_device.mode) {
case TICKDEV_MODE_PERIODIC:
if(!cpus_empty(tick_broadcast_mask))
Expand Down
16 changes: 10 additions & 6 deletions kernel/time/tick-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,12 +318,17 @@ static void tick_resume(void)
{
struct tick_device *td = &__get_cpu_var(tick_cpu_device);
unsigned long flags;
int broadcast = tick_resume_broadcast();

spin_lock_irqsave(&tick_device_lock, flags);
if (td->mode == TICKDEV_MODE_PERIODIC)
tick_setup_periodic(td->evtdev, 0);
else
tick_resume_oneshot();
clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);

if (!broadcast) {
if (td->mode == TICKDEV_MODE_PERIODIC)
tick_setup_periodic(td->evtdev, 0);
else
tick_resume_oneshot();
}
spin_unlock_irqrestore(&tick_device_lock, flags);
}

Expand Down Expand Up @@ -360,8 +365,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
break;

case CLOCK_EVT_NOTIFY_RESUME:
if (!tick_resume_broadcast())
tick_resume();
tick_resume();
break;

default:
Expand Down

0 comments on commit 18de5bc

Please sign in to comment.