Commit 2a2bac60 authored by Venkatesh Pallipadi's avatar Venkatesh Pallipadi Committed by Greg Kroah-Hartman

clockevents: prevent clockevent event_handler ending up handler_noop

commit 7c1e7689 upstream

There is a ordering related problem with clockevents code, due to which
clockevents_register_device() called after tickless/highres switch
will not work. The new clockevent ends up with clockevents_handle_noop as
event handler, resulting in no timer activity.

The problematic path seems to be

* old device already has hrtimer_interrupt as the event_handler
* new clockevent device registers with a higher rating
* tick_check_new_device() is called
  * clockevents_exchange_device() gets called
    * old->event_handler is set to clockevents_handle_noop
  * tick_setup_device() is called for the new device
    * which sets new->event_handler using the old->event_handler which is noop.

Change the ordering so that new device inherits the proper handler.

This does not have any issue in normal case as most likely all the clockevent
devices are setup before the highres switch. But, can potentially be affecting
some corner case where HPET force detect happens after the highres switch.
This was a problem with HPET in MSI mode code that we have been experimenting
with.
Signed-off-by: default avatarVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: default avatarShaohua Li <shaohua.li@intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 579b4b38
...@@ -127,6 +127,8 @@ extern int clockevents_register_notifier(struct notifier_block *nb); ...@@ -127,6 +127,8 @@ extern int clockevents_register_notifier(struct notifier_block *nb);
extern int clockevents_program_event(struct clock_event_device *dev, extern int clockevents_program_event(struct clock_event_device *dev,
ktime_t expires, ktime_t now); ktime_t expires, ktime_t now);
extern void clockevents_handle_noop(struct clock_event_device *dev);
#ifdef CONFIG_GENERIC_CLOCKEVENTS #ifdef CONFIG_GENERIC_CLOCKEVENTS
extern void clockevents_notify(unsigned long reason, void *arg); extern void clockevents_notify(unsigned long reason, void *arg);
#else #else
......
...@@ -177,7 +177,7 @@ void clockevents_register_device(struct clock_event_device *dev) ...@@ -177,7 +177,7 @@ void clockevents_register_device(struct clock_event_device *dev)
/* /*
* Noop handler when we shut down an event device * Noop handler when we shut down an event device
*/ */
static void clockevents_handle_noop(struct clock_event_device *dev) void clockevents_handle_noop(struct clock_event_device *dev)
{ {
} }
...@@ -199,7 +199,6 @@ void clockevents_exchange_device(struct clock_event_device *old, ...@@ -199,7 +199,6 @@ void clockevents_exchange_device(struct clock_event_device *old,
* released list and do a notify add later. * released list and do a notify add later.
*/ */
if (old) { if (old) {
old->event_handler = clockevents_handle_noop;
clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
list_del(&old->list); list_del(&old->list);
list_add(&old->list, &clockevents_released); list_add(&old->list, &clockevents_released);
......
...@@ -161,6 +161,7 @@ static void tick_setup_device(struct tick_device *td, ...@@ -161,6 +161,7 @@ static void tick_setup_device(struct tick_device *td,
} else { } else {
handler = td->evtdev->event_handler; handler = td->evtdev->event_handler;
next_event = td->evtdev->next_event; next_event = td->evtdev->next_event;
td->evtdev->event_handler = clockevents_handle_noop;
} }
td->evtdev = newdev; td->evtdev = newdev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment