[PATCH 1/5] generic clocksource updates

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



A number of changes to the clocksource infrastructur:
- use xtime_lock instead of clocksource_lock, so it's easier to
  synchronize the clocksource switch for gettimeofday.
- add a few clock state variables (instead of making them global).
- clocksource_get_nsec_offset(): this should become clocksource specific
  later.
- select_clocks: immediately switch clocksource.
- cleanup naming to put the subsystem name in front

Signed-off-by: Roman Zippel <[email protected]>

---

 include/linux/clocksource.h |   33 +++++++-------
 kernel/Makefile             |    1 
 kernel/time/clocksource.c   |   99 +++++++++++++++++---------------------------
 kernel/time/jiffies.c       |   16 ++++---
 4 files changed, 67 insertions(+), 82 deletions(-)

Index: linux-2.6-mm/include/linux/clocksource.h
===================================================================
--- linux-2.6-mm.orig/include/linux/clocksource.h	2006-04-02 06:53:29.000000000 +0200
+++ linux-2.6-mm/include/linux/clocksource.h	2006-04-02 16:12:28.000000000 +0200
@@ -45,9 +45,8 @@ typedef u64 cycle_t;
  * @mult:		cycle to nanosecond multiplier
  * @shift:		cycle to nanosecond divisor (power of two)
  * @update_callback:	called when safe to alter clocksource values
- * @is_continuous:	defines if clocksource is free-running.
- * @interval_cycles:	Used internally by timekeeping core, please ignore.
- * @interval_snsecs:	Used internally by timekeeping core, please ignore.
+ * @cycle_update:	Used internally by timekeeping core, please ignore.
+ * @xtime_update:	Used internally by timekeeping core, please ignore.
  */
 struct clocksource {
 	char *name;
@@ -58,11 +57,11 @@ struct clocksource {
 	u32 mult;
 	u32 shift;
 	int (*update_callback)(void);
-	int is_continuous;
 
 	/* timekeeping specific data, ignore */
-	cycle_t interval_cycles;
-	u64 interval_snsecs;
+	u64 cycles_last, cycle_update;
+	u64 xtime_nsec, xtime_update;
+	s64 ntp_error;
 };
 
 
@@ -145,7 +144,7 @@ static inline s64 cyc2ns(struct clocksou
 }
 
 /**
- * calculate_clocksource_interval - Calculates a clocksource interval struct
+ * clocksource_calculate_interval - Calculates a clocksource interval struct
  *
  * @c:		Pointer to clocksource.
  * @length_nsec: Desired interval length in nanoseconds.
@@ -155,8 +154,8 @@ static inline s64 cyc2ns(struct clocksou
  *
  * Unless you're the timekeeping code, you should not be using this!
  */
-static inline void calculate_clocksource_interval(struct clocksource *c,
-						unsigned long length_nsec)
+static inline void clocksource_calculate_interval(struct clocksource *c,
+						  unsigned long length_nsec)
 {
 	u64 tmp;
 
@@ -166,16 +165,18 @@ static inline void calculate_clocksource
 	tmp += c->mult/2;
 	do_div(tmp, c->mult);
 
-	c->interval_cycles = (cycle_t)tmp;
-	if(c->interval_cycles == 0)
-		c->interval_cycles = 1;
+	c->cycle_update = (cycle_t)tmp;
+	if (c->cycle_update == 0)
+		c->cycle_update = 1;
 
-	c->interval_snsecs = (u64)c->interval_cycles * c->mult;
+	c->xtime_update = (u64)c->cycle_update * c->mult;
 }
 
 /* used to install a new clocksource */
-int register_clocksource(struct clocksource*);
-void reselect_clocksource(void);
-struct clocksource* get_next_clocksource(void);
+int clocksource_register(struct clocksource *);
+void clocksource_reselect(void);
+unsigned long clocksource_get_nsec_offset(struct clocksource *cs);
+
+extern struct clocksource *curr_clocksource;
 
 #endif /* _LINUX_CLOCKSOURCE_H */
Index: linux-2.6-mm/kernel/Makefile
===================================================================
--- linux-2.6-mm.orig/kernel/Makefile	2006-04-02 06:52:06.000000000 +0200
+++ linux-2.6-mm/kernel/Makefile	2006-04-02 16:11:03.000000000 +0200
@@ -10,6 +10,7 @@ obj-y     = sched.o fork.o exec_domain.o
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o
 
+obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
 obj-$(CONFIG_FUTEX) += futex.o
 ifeq ($(CONFIG_COMPAT),y)
Index: linux-2.6-mm/kernel/time/clocksource.c
===================================================================
--- linux-2.6-mm.orig/kernel/time/clocksource.c	2006-04-02 06:53:29.000000000 +0200
+++ linux-2.6-mm/kernel/time/clocksource.c	2006-04-02 16:11:28.000000000 +0200
@@ -35,57 +35,28 @@ extern struct clocksource clocksource_ji
 /*[Clocksource internal variables]---------
  * curr_clocksource:
  *	currently selected clocksource. Initialized to clocksource_jiffies.
- * next_clocksource:
- *	pending next selected clocksource.
  * clocksource_list:
  *	linked list with the registered clocksources
- * clocksource_lock:
- *	protects manipulations to curr_clocksource and next_clocksource
- *	and the clocksource_list
  * override_name:
  *	Name of the user-specified clocksource.
  */
-static struct clocksource *curr_clocksource = &clocksource_jiffies;
-static struct clocksource *next_clocksource;
+struct clocksource *curr_clocksource = &clocksource_jiffies;
 static LIST_HEAD(clocksource_list);
-static DEFINE_SPINLOCK(clocksource_lock);
 static char override_name[32];
-static int finished_booting;
 
-/* clocksource_done_booting - Called near the end of bootup
- *
- * Hack to avoid lots of clocksource churn at boot time
- */
-static int clocksource_done_booting(void)
+unsigned long clocksource_get_nsec_offset(struct clocksource *cs)
 {
-	finished_booting = 1;
-	return 0;
-}
+	cycle_t cycle_delta;
 
-late_initcall(clocksource_done_booting);
+	cycle_delta = (cs->read() - cs->cycles_last) & cs->mask;
 
-/**
- * get_next_clocksource - Returns the selected clocksource
- *
- */
-struct clocksource *get_next_clocksource(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&clocksource_lock, flags);
-	if (next_clocksource && finished_booting) {
-		curr_clocksource = next_clocksource;
-		next_clocksource = NULL;
-	}
-	spin_unlock_irqrestore(&clocksource_lock, flags);
-
-	return curr_clocksource;
+	return (cs->xtime_nsec + cycle_delta * cs->mult) >> cs->shift;
 }
 
 /**
  * select_clocksource - Finds the best registered clocksource.
  *
- * Private function. Must hold clocksource_lock when called.
+ * Private function. Must hold xtime_lock when called.
  *
  * Looks through the list of registered clocksources, returning
  * the one with the highest rating value. If there is a clocksource
@@ -114,6 +85,17 @@ static struct clocksource *select_clocks
 		 	best = src;
 	}
 
+	if (curr_clocksource != best) {
+		printk("switching to clocksource %s\n", best->name);
+		if (curr_clocksource)
+			xtime.tv_nsec = clocksource_get_nsec_offset(curr_clocksource);
+		best->ntp_error = 0;
+		best->cycles_last = best->read();
+		best->xtime_nsec = (u64)xtime.tv_nsec << best->shift;
+		clocksource_calculate_interval(best, tick_nsec);
+		curr_clocksource = best;
+	}
+
 	return best;
 }
 
@@ -121,7 +103,7 @@ static struct clocksource *select_clocks
  * is_registered_source - Checks if clocksource is registered
  * @c:		pointer to a clocksource
  *
- * Private helper function. Must hold clocksource_lock when called.
+ * Private helper function. Must hold xtime_lock when called.
  *
  * Returns one if the clocksource is already registered, zero otherwise.
  */
@@ -142,48 +124,45 @@ static int is_registered_source(struct c
 }
 
 /**
- * register_clocksource - Used to install new clocksources
+ * clocksource_register - Used to install new clocksources
  * @t:		clocksource to be registered
  *
  * Returns -EBUSY if registration fails, zero otherwise.
  */
-int register_clocksource(struct clocksource *c)
+int clocksource_register(struct clocksource *c)
 {
 	int ret = 0;
-	unsigned long flags;
 
-	spin_lock_irqsave(&clocksource_lock, flags);
+	write_seqlock_irq(&xtime_lock);
 	/* check if clocksource is already registered */
 	if (is_registered_source(c)) {
-		printk("register_clocksource: Cannot register %s. "
+		printk("clocksource_register: Cannot register %s. "
 			"Already registered!", c->name);
 		ret = -EBUSY;
 	} else {
 		/* register it */
  		list_add(&c->list, &clocksource_list);
 		/* scan the registered clocksources, and pick the best one */
-		next_clocksource = select_clocksource();
+		select_clocksource();
 	}
-	spin_unlock_irqrestore(&clocksource_lock, flags);
+	write_sequnlock_irq(&xtime_lock);
 	return ret;
 }
 
-EXPORT_SYMBOL(register_clocksource);
+EXPORT_SYMBOL(clocksource_register);
 
 /**
- * reselect_clocksource - Rescan list for next clocksource
+ * clocksource_reselect - Rescan list for next clocksource
  *
  * A quick helper function to be used if a clocksource changes its
  * rating. Forces the clocksource list to be re-scaned for the best
  * clocksource.
  */
-void reselect_clocksource(void)
+void clocksource_reselect(void)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&clocksource_lock, flags);
-	next_clocksource = select_clocksource();
-	spin_unlock_irqrestore(&clocksource_lock, flags);
+	write_seqlock_irq(&xtime_lock);
+	select_clocksource();
+	write_sequnlock_irq(&xtime_lock);
 }
 
 /**
@@ -198,9 +177,9 @@ sysfs_show_current_clocksources(struct s
 {
 	char *curr = buf;
 
-	spin_lock_irq(&clocksource_lock);
+	write_seqlock_irq(&xtime_lock);
 	curr += sprintf(curr, "%s ", curr_clocksource->name);
-	spin_unlock_irq(&clocksource_lock);
+	write_sequnlock_irq(&xtime_lock);
 
 	curr += sprintf(curr, "\n");
 
@@ -230,16 +209,16 @@ static ssize_t sysfs_override_clocksourc
 	if (count < 1)
 		return -EINVAL;
 
-	spin_lock_irq(&clocksource_lock);
+	write_seqlock_irq(&xtime_lock);
 
 	/* copy the name given: */
 	memcpy(override_name, buf, count);
 	override_name[count] = 0;
 
 	/* try to select it: */
-	next_clocksource = select_clocksource();
+	select_clocksource();
 
-	spin_unlock_irq(&clocksource_lock);
+	write_sequnlock_irq(&xtime_lock);
 
 	return ret;
 }
@@ -257,14 +236,14 @@ sysfs_show_available_clocksources(struct
 	struct list_head *tmp;
 	char *curr = buf;
 
-	spin_lock_irq(&clocksource_lock);
+	write_seqlock_irq(&xtime_lock);
 	list_for_each(tmp, &clocksource_list) {
 		struct clocksource *src;
 
 		src = list_entry(tmp, struct clocksource, list);
 		curr += sprintf(curr, "%s ", src->name);
 	}
-	spin_unlock_irq(&clocksource_lock);
+	write_sequnlock_irq(&xtime_lock);
 
 	curr += sprintf(curr, "\n");
 
@@ -318,10 +297,10 @@ device_initcall(init_clocksource_sysfs);
 static int __init boot_override_clocksource(char* str)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&clocksource_lock, flags);
+	write_seqlock_irqsave(&xtime_lock, flags);
 	if (str)
 		strlcpy(override_name, str, sizeof(override_name));
-	spin_unlock_irqrestore(&clocksource_lock, flags);
+	write_sequnlock_irqrestore(&xtime_lock, flags);
 	return 1;
 }
 
Index: linux-2.6-mm/kernel/time/jiffies.c
===================================================================
--- linux-2.6-mm.orig/kernel/time/jiffies.c	2006-04-02 06:53:29.000000000 +0200
+++ linux-2.6-mm/kernel/time/jiffies.c	2006-04-02 06:53:29.000000000 +0200
@@ -50,10 +50,7 @@
  */
 #define JIFFIES_SHIFT	8
 
-static cycle_t jiffies_read(void)
-{
-	return (cycle_t) jiffies;
-}
+static cycle_t jiffies_read(void);
 
 struct clocksource clocksource_jiffies = {
 	.name		= "jiffies",
@@ -62,12 +59,19 @@ struct clocksource clocksource_jiffies =
 	.mask		= 0xffffffff, /*32bits*/
 	.mult		= NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
 	.shift		= JIFFIES_SHIFT,
-	.is_continuous	= 0, /* tick based, not free running */
+
+	.cycle_update	= 1,
+	.xtime_update	= NSEC_PER_JIFFY << JIFFIES_SHIFT,
 };
 
+static cycle_t jiffies_read(void)
+{
+	return clocksource_jiffies.cycles_last + 1;
+}
+
 static int __init init_jiffies_clocksource(void)
 {
-	return register_clocksource(&clocksource_jiffies);
+	return clocksource_register(&clocksource_jiffies);
 }
 
 module_init(init_jiffies_clocksource);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux