timekeeping: Allow runtime PM from change_clocksource()
[linux-2.6-microblaze.git] / kernel / time / timekeeping.c
index 77bafd8..81fe2a3 100644 (file)
@@ -1427,35 +1427,45 @@ static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset)
 static int change_clocksource(void *data)
 {
        struct timekeeper *tk = &tk_core.timekeeper;
-       struct clocksource *new, *old;
+       struct clocksource *new, *old = NULL;
        unsigned long flags;
+       bool change = false;
 
        new = (struct clocksource *) data;
 
-       raw_spin_lock_irqsave(&timekeeper_lock, flags);
-       write_seqcount_begin(&tk_core.seq);
-
-       timekeeping_forward_now(tk);
        /*
         * If the cs is in module, get a module reference. Succeeds
         * for built-in code (owner == NULL) as well.
         */
        if (try_module_get(new->owner)) {
-               if (!new->enable || new->enable(new) == 0) {
-                       old = tk->tkr_mono.clock;
-                       tk_setup_internals(tk, new);
-                       if (old->disable)
-                               old->disable(old);
-                       module_put(old->owner);
-               } else {
+               if (!new->enable || new->enable(new) == 0)
+                       change = true;
+               else
                        module_put(new->owner);
-               }
        }
+
+       raw_spin_lock_irqsave(&timekeeper_lock, flags);
+       write_seqcount_begin(&tk_core.seq);
+
+       timekeeping_forward_now(tk);
+
+       if (change) {
+               old = tk->tkr_mono.clock;
+               tk_setup_internals(tk, new);
+       }
+
        timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
 
        write_seqcount_end(&tk_core.seq);
        raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
+       if (old) {
+               if (old->disable)
+                       old->disable(old);
+
+               module_put(old->owner);
+       }
+
        return 0;
 }