Skip to contentSkip to conversation

clocksource: add enable() and disable() callbacks

PATCH In review Magnus Damm 3 participants 5 messages Dec 11, 2008 – Dec 12, 2008 Timekeeping, clocksource core, NTP, alarmtimer

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 clocksource: add enable() and disable() callbacks

From: Magnus Damm <[email protected]>

Add enable() and disable() callbacks for clocksources. This allows us to put unused clocksources in power save mode. The functions clocksource_enable() and clocksource_disable() wrap the callbacks and are inserted in the timekeeping code to enable before use and disable after switching to a new clocksource.

---

Same as before, but applies on top of the new read() patch.

 include/linux/clocksource.h |   31 +++++++++++++++++++++++++++++++
 kernel/time/timekeeping.c   |   12 +++++++++---
 2 files changed, 40 insertions(+), 3 deletions(-)
include/linux/clocksource.h +31 -0
@@ -43,6 +43,8 @@ struct clocksource;
  *				The ideal clocksource. A must-use where
  *				available.
  * @read:		returns a cycle value, passes clocksource as argument
+ * @enable:		optional function to enable the clocksource
+ * @disable:		optional function to disable the clocksource
  * @mask:		bitmask for two's complement
  *			subtraction of non 64 bit counters
  * @mult:		cycle to nanosecond multiplier (adjusted by NTP)
@@ -62,6 +64,8 @@ struct clocksource {
 	struct list_head list;
 	int rating;
 	cycle_t (*read)(struct clocksource *cs);
+	int (*enable)(struct clocksource *cs);
+	void (*disable)(struct clocksource *cs);
 	cycle_t mask;
 	u32 mult;
 	u32 mult_orig;
@@ -174,6 +178,33 @@ static inline cycle_t clocksource_read(s
 }
 
 /**
+ * clocksource_enable: - enable clocksource
+ * @cs:		pointer to clocksource
+ *
+ * Enables the specified clocksource. The clocksource callback
+ * function should start up the hardware and setup mult and field
+ * members of struct clocksource to reflect hardware capabilities.
+ */
+static inline int clocksource_enable(struct clocksource *cs)
+{
+	return cs->enable ? cs->enable(cs) : 0;
+}
+
+/**
+ * clocksource_disable: - disable clocksource
+ * @cs:		pointer to clocksource
+ *
+ * Disables the specified clocksource. The clocksource callback
+ * function should power down the now unused hardware block to
+ * save power.
+ */
+static inline void clocksource_disable(struct clocksource *cs)
+{
+	if (cs->disable)
+		cs->disable(cs);
+}
+
+/**
  * cyc2ns - converts clocksource cycles to nanoseconds
  * @cs:		Pointer to clocksource
  * @cycles:	Cycles
kernel/time/timekeeping.c +9 -3
@@ -184,7 +184,7 @@ EXPORT_SYMBOL(do_settimeofday);
  */
 static void change_clocksource(void)
 {
-	struct clocksource *new;
+	struct clocksource *new, *old;
 
 	new = clocksource_get_next();
 
@@ -193,11 +193,16 @@ static void change_clocksource(void)
 
 	clocksource_forward_now();
 
-	new->raw_time = clock->raw_time;
+	if (clocksource_enable(new))
+		return;
 
+	new->raw_time = clock->raw_time;
+	old = clock;
 	clock = new;
+	clocksource_disable(old);
+
 	clock->cycle_last = 0;
-	clock->cycle_last = clocksource_read(new);
+	clock->cycle_last = clocksource_read(clock);
 	clock->error = 0;
 	clock->xtime_nsec = 0;
 	clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
@@ -293,6 +298,7 @@ void __init timekeeping_init(void)
 	ntp_init();
 
 	clock = clocksource_get_next();
+	clocksource_enable(clock);
 	clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
 	clock->cycle_last = clocksource_read(clock);
 
#1 lore raw
Quoted 8 lines · On Thu, 11 Dec 2008 20:49:09 +0900 Magnus Damm <[email protected]> wrote:

From: Magnus Damm <[email protected]>

Add enable() and disable() callbacks for clocksources. This allows us to put unused clocksources in power save mode. The functions clocksource_enable() and clocksource_disable() wrap the callbacks and are inserted in the timekeeping code to enable before use and disable after switching to a new clocksource.

Quoted 5 lines

---

Same as before, but applies on top of the new read() patch.

I asusme we'll be seeing some patches which _use_ these changes?

#2 lore raw
Quoted 10 lines · Andrew Morton
Quoted 8 lines · On Thu, 11 Dec 2008 20:49:09 +0900 Magnus Damm <[email protected]> wrote:

From: Magnus Damm <[email protected]>

Add enable() and disable() callbacks for clocksources. This allows us to put unused clocksources in power save mode. The functions clocksource_enable() and clocksource_disable() wrap the callbacks and are inserted in the timekeeping code to enable before use and disable after switching to a new clocksource.

Quoted 7 lines
Quoted 5 lines

---

Same as before, but applies on top of the new read() patch.

I asusme we'll be seeing some patches which _use_ these changes?

I've send a few iterations of my SuperH CMT timer patches to the linux-sh list, but I'd be happy to post next version to lkml instead if you prefer that!

The CMT driver also needs the following patches:

[PATCH] clocksource: pass clocksource to read() callback [PATCH][RFC] early platform driver support

Any comments on the early platform driver code?

Thanks,

/ magnus

#3 lore raw
In reply to Magnus Damm

include/linux/clocksource.h static inline cycle_t clocksource_read(s · line 205

Quoted 10 lines · Magnus Damm
include/linux/clocksource.h +9 -0
+static inline int clocksource_enable(struct clocksource *cs)
+{
+	return cs->enable ? cs->enable(cs) : 0;
+}
 
+static inline void clocksource_disable(struct clocksource *cs)
+{
+	if (cs->disable)
+		cs->disable(cs);
+}

why have the two different styles? The first one should be:

	if (cs->enable)
		return cs->enable(cs);
	return 0;

kernel/time/timekeeping.c static void change_clocksource(void) · line 197

Quoted 7 lines
kernel/time/timekeeping.c +2 -1
@@ -193,11 +193,16 @@ static void change_clocksource(void)
 
 	clocksource_forward_now();
 
-	new->raw_time = clock->raw_time;
+	if (clocksource_enable(new))
+		return;

that looks fragile to me: if the enable fails we'll return silently, while change_clocksource() assumes that things went fine. At least put a WARN_ON_ONCE() in there.

also, why does it have to fail? If a clocksource cannot be enabled it should not be offered as a clocksource.

kernel/time/timekeeping.c static void change_clocksource(void) · line 202

Quoted 1 line
kernel/time/timekeeping.c +1 -0
+	clocksource_disable(old);

i do agree with the core purpose here, to allow lowlevel code to deactivate unused clocksources.

John, Thomas, what's your take on this?

Ingo

#4 lore raw

Hi Ingo,

Quoted 14 lines · Ingo Molnar

include/linux/clocksource.h static inline cycle_t clocksource_read(s · line 205

Quoted 10 lines · Magnus Damm
include/linux/clocksource.h +9 -0
+static inline int clocksource_enable(struct clocksource *cs)
+{
+     return cs->enable ? cs->enable(cs) : 0;
+}
 
+static inline void clocksource_disable(struct clocksource *cs)
+{
+     if (cs->disable)
+             cs->disable(cs);
+}

why have the two different styles? The first one should be:

Quoted 3 lines
       if (cs->enable)
               return cs->enable(cs);
       return 0;

Sure, that's fine too.

Quoted 11 lines

kernel/time/timekeeping.c static void change_clocksource(void) · line 197

Quoted 7 lines
kernel/time/timekeeping.c +2 -1
@@ -193,11 +193,16 @@ static void change_clocksource(void)
 
      clocksource_forward_now();
 
-     new->raw_time = clock->raw_time;
+     if (clocksource_enable(new))
+             return;

that looks fragile to me: if the enable fails we'll return silently, while change_clocksource() assumes that things went fine. At least put a WARN_ON_ONCE() in there.

Yeah, John and I discussed this before. What we really want it to move the failing clocksource out of the list of available clocksources. That type of change is pretty intrusive though, and I rather see it as a separate topic.

Quoted 2 lines

also, why does it have to fail? If a clocksource cannot be enabled it should not be offered as a clocksource.

Right. I guess most clocksource drivers for embedded platforms will tie in the clock framework and use clk_enable() and clk_disable(). clk_enable() returns an int.

Quoted 4 lines

kernel/time/timekeeping.c static void change_clocksource(void) · line 202

Quoted 1 line
kernel/time/timekeeping.c +1 -0
+     clocksource_disable(old);

i do agree with the core purpose here, to allow lowlevel code to deactivate unused clocksources.

That's good! I hope we can sort out the details then!

Cheers,

/ magnus