Skip to content

Commit

Permalink
clockevents: prevent mode mismatch on cpu online
Browse files Browse the repository at this point in the history
Impact: timer hang on CPU online observed on AMD C1E systems

When a CPU is brought online then the broadcast machinery can
be in the one shot state already. Check this and setup the timer 
device of the new CPU in one shot mode so the broadcast code
can pick up the next_event value correctly.

Another AMD C1E oddity, as we switch to broadcast immediately and
not after the full bring up via the ACPI cpu idle code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Sep 23, 2008
1 parent 3027456 commit 27ce4cb
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 1 deletion.
8 changes: 8 additions & 0 deletions kernel/time/tick-broadcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,4 +575,12 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}

/*
* Check, whether the broadcast device is in one shot mode
*/
int tick_broadcast_oneshot_active(void)
{
return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
}

#endif
3 changes: 2 additions & 1 deletion kernel/time/tick-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
if (!tick_device_is_functional(dev))
return;

if (dev->features & CLOCK_EVT_FEAT_PERIODIC) {
if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
!tick_broadcast_oneshot_active()) {
clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
} else {
unsigned long seq;
Expand Down
2 changes: 2 additions & 0 deletions kernel/time/tick-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extern void tick_broadcast_oneshot_control(unsigned long reason);
extern void tick_broadcast_switch_to_oneshot(void);
extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
extern int tick_broadcast_oneshot_active(void);
# else /* BROADCAST */
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
{
Expand All @@ -43,6 +44,7 @@ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
static inline void tick_broadcast_oneshot_control(unsigned long reason) { }
static inline void tick_broadcast_switch_to_oneshot(void) { }
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
static inline int tick_broadcast_oneshot_active(void) { return 0; }
# endif /* !BROADCAST */

#else /* !ONESHOT */
Expand Down

0 comments on commit 27ce4cb

Please sign in to comment.