clocksource: add enable() and disable() callbacks
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);
Quoted 8 lines · On Thu, 11 Dec 2008 20:49:09 +0900 Magnus Damm <[email protected]> wrote:
From: Magnus Damm <[email protected]>
Add
enable()anddisable()callbacks for clocksources. This allows us to put unused clocksources in power save mode. The functionsclocksource_enable()andclocksource_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
Signed-off-by Magnus Damm <[email protected]>Acked-by John Stultz <[email protected]>---
Same as before, but applies on top of the new
read()patch.
I asusme we'll be seeing some patches which _use_ these changes?
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()anddisable()callbacks for clocksources. This allows us to put unused clocksources in power save mode. The functionsclocksource_enable()andclocksource_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
Signed-off-by Magnus Damm <[email protected]>Acked-by John Stultz <[email protected]>---
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
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
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 aWARN_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