timekeeping: Move reset of cycle_last for tsc clocksource to tsc
[safe/jmp/linux-2.6] / kernel / time / clockevents.c
index 67932ea..a6dcd67 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/notifier.h>
 #include <linux/smp.h>
 #include <linux/sysdev.h>
+#include <linux/tick.h>
 
 /* The registered clock event devices */
 static LIST_HEAD(clockevent_devices);
@@ -41,6 +42,11 @@ unsigned long clockevent_delta2ns(unsigned long latch,
 {
        u64 clc = ((u64) latch << evt->shift);
 
+       if (unlikely(!evt->mult)) {
+               evt->mult = 1;
+               WARN_ON(1);
+       }
+
        do_div(clc, evt->mult);
        if (clc < 1000)
                clc = 1000;
@@ -49,6 +55,7 @@ unsigned long clockevent_delta2ns(unsigned long latch,
 
        return (unsigned long) clc;
 }
+EXPORT_SYMBOL_GPL(clockevent_delta2ns);
 
 /**
  * clockevents_set_mode - set the operating mode of a clock event device
@@ -63,10 +70,31 @@ void clockevents_set_mode(struct clock_event_device *dev,
        if (dev->mode != mode) {
                dev->set_mode(mode, dev);
                dev->mode = mode;
+
+               /*
+                * A nsec2cyc multiplicator of 0 is invalid and we'd crash
+                * on it, so fix it up and emit a warning:
+                */
+               if (mode == CLOCK_EVT_MODE_ONESHOT) {
+                       if (unlikely(!dev->mult)) {
+                               dev->mult = 1;
+                               WARN_ON(1);
+                       }
+               }
        }
 }
 
 /**
+ * clockevents_shutdown - shutdown the device and clear next_event
+ * @dev:       device to shutdown
+ */
+void clockevents_shutdown(struct clock_event_device *dev)
+{
+       clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+       dev->next_event.tv64 = KTIME_MAX;
+}
+
+/**
  * clockevents_program_event - Reprogram the clock event device.
  * @expires:   absolute expiry time (monotonic clock)
  *
@@ -78,6 +106,11 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
        unsigned long long clc;
        int64_t delta;
 
+       if (unlikely(expires.tv64 < 0)) {
+               WARN_ON_ONCE(1);
+               return -ETIME;
+       }
+
        delta = ktime_to_ns(ktime_sub(expires, now));
 
        if (delta <= 0)
@@ -113,16 +146,6 @@ int clockevents_register_notifier(struct notifier_block *nb)
        return ret;
 }
 
-/**
- * clockevents_unregister_notifier - unregister a clock events change listener
- */
-void clockevents_unregister_notifier(struct notifier_block *nb)
-{
-       spin_lock(&clockevents_lock);
-       raw_notifier_chain_unregister(&clockevents_chain, nb);
-       spin_unlock(&clockevents_lock);
-}
-
 /*
  * Notify about a clock event change. Called with clockevents_lock
  * held.
@@ -133,7 +156,7 @@ static void clockevents_do_notify(unsigned long reason, void *dev)
 }
 
 /*
- * Called after a notify add to make devices availble which were
+ * Called after a notify add to make devices available which were
  * released from the notifier call.
  */
 static void clockevents_notify_released(void)
@@ -156,6 +179,7 @@ static void clockevents_notify_released(void)
 void clockevents_register_device(struct clock_event_device *dev)
 {
        BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
+       BUG_ON(!dev->cpumask);
 
        spin_lock(&clockevents_lock);
 
@@ -165,11 +189,12 @@ void clockevents_register_device(struct clock_event_device *dev)
 
        spin_unlock(&clockevents_lock);
 }
+EXPORT_SYMBOL_GPL(clockevents_register_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)
 {
 }
 
@@ -191,7 +216,6 @@ void clockevents_exchange_device(struct clock_event_device *old,
         * released list and do a notify add later.
         */
        if (old) {
-               old->event_handler = clockevents_handle_noop;
                clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
                list_del(&old->list);
                list_add(&old->list, &clockevents_released);
@@ -199,57 +223,19 @@ void clockevents_exchange_device(struct clock_event_device *old,
 
        if (new) {
                BUG_ON(new->mode != CLOCK_EVT_MODE_UNUSED);
-               clockevents_set_mode(new, CLOCK_EVT_MODE_SHUTDOWN);
+               clockevents_shutdown(new);
        }
        local_irq_restore(flags);
 }
 
-/**
- * clockevents_request_device
- */
-struct clock_event_device *clockevents_request_device(unsigned int features,
-                                                     cpumask_t cpumask)
-{
-       struct clock_event_device *cur, *dev = NULL;
-       struct list_head *tmp;
-
-       spin_lock(&clockevents_lock);
-
-       list_for_each(tmp, &clockevent_devices) {
-               cur = list_entry(tmp, struct clock_event_device, list);
-
-               if ((cur->features & features) == features &&
-                   cpus_equal(cpumask, cur->cpumask)) {
-                       if (!dev || dev->rating < cur->rating)
-                               dev = cur;
-               }
-       }
-
-       clockevents_exchange_device(NULL, dev);
-
-       spin_unlock(&clockevents_lock);
-
-       return dev;
-}
-
-/**
- * clockevents_release_device
- */
-void clockevents_release_device(struct clock_event_device *dev)
-{
-       spin_lock(&clockevents_lock);
-
-       clockevents_exchange_device(dev, NULL);
-       clockevents_notify_released();
-
-       spin_unlock(&clockevents_lock);
-}
-
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
 /**
  * clockevents_notify - notification about relevant events
  */
 void clockevents_notify(unsigned long reason, void *arg)
 {
+       struct list_head *node, *tmp;
+
        spin_lock(&clockevents_lock);
        clockevents_do_notify(reason, arg);
 
@@ -259,13 +245,8 @@ void clockevents_notify(unsigned long reason, void *arg)
                 * Unregister the clock event devices which were
                 * released from the users in the notify chain.
                 */
-               while (!list_empty(&clockevents_released)) {
-                       struct clock_event_device *dev;
-
-                       dev = list_entry(clockevents_released.next,
-                                        struct clock_event_device, list);
-                       list_del(&dev->list);
-               }
+               list_for_each_safe(node, tmp, &clockevents_released)
+                       list_del(node);
                break;
        default:
                break;
@@ -273,73 +254,4 @@ void clockevents_notify(unsigned long reason, void *arg)
        spin_unlock(&clockevents_lock);
 }
 EXPORT_SYMBOL_GPL(clockevents_notify);
-
-#ifdef CONFIG_SYSFS
-
-/**
- * clockevents_show_registered - sysfs interface for listing clockevents
- * @dev:       unused
- * @buf:       char buffer to be filled with clock events list
- *
- * Provides sysfs interface for listing registered clock event devices
- */
-static ssize_t clockevents_show_registered(struct sys_device *dev, char *buf)
-{
-       struct list_head *tmp;
-       char *p = buf;
-       int cpu;
-
-       spin_lock(&clockevents_lock);
-
-       list_for_each(tmp, &clockevent_devices) {
-               struct clock_event_device *ce;
-
-               ce = list_entry(tmp, struct clock_event_device, list);
-               p += sprintf(p, "%-20s F:%04x M:%d", ce->name,
-                            ce->features, ce->mode);
-               p += sprintf(p, " C:");
-               if (!cpus_equal(ce->cpumask, cpu_possible_map)) {
-                       for_each_cpu_mask(cpu, ce->cpumask)
-                               p += sprintf(p, " %d", cpu);
-               } else {
-                       /*
-                        * FIXME: Add the cpu which is handling this sucker
-                        */
-               }
-               p += sprintf(p, "\n");
-       }
-
-       spin_unlock(&clockevents_lock);
-
-       return p - buf;
-}
-
-/*
- * Sysfs setup bits:
- */
-static SYSDEV_ATTR(registered, 0600,
-                  clockevents_show_registered, NULL);
-
-static struct sysdev_class clockevents_sysclass = {
-       set_kset_name("clockevents"),
-};
-
-static struct sys_device clockevents_sys_device = {
-       .id     = 0,
-       .cls    = &clockevents_sysclass,
-};
-
-static int __init clockevents_sysfs_init(void)
-{
-       int error = sysdev_class_register(&clockevents_sysclass);
-
-       if (!error)
-               error = sysdev_register(&clockevents_sys_device);
-       if (!error)
-               error = sysdev_create_file(
-                               &clockevents_sys_device,
-                               &attr_registered);
-       return error;
-}
-device_initcall(clockevents_sysfs_init);
 #endif