2008-12-11 11:51:14

by Magnus Damm

[permalink] [raw]
Subject: [PATCH] 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.

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.

include/linux/clocksource.h | 31 +++++++++++++++++++++++++++++++
kernel/time/timekeeping.c | 12 +++++++++---
2 files changed, 40 insertions(+), 3 deletions(-)

--- 0005/include/linux/clocksource.h
+++ work/include/linux/clocksource.h 2008-12-11 19:52:25.000000000 +0900
@@ -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
--- 0004/kernel/time/timekeeping.c
+++ work/kernel/time/timekeeping.c 2008-12-11 19:51:16.000000000 +0900
@@ -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);


2008-12-12 03:14:40

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] clocksource: add enable() and disable() callbacks

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.
>
> 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?

2008-12-12 03:35:00

by Magnus Damm

[permalink] [raw]
Subject: Re: [PATCH] clocksource: add enable() and disable() callbacks

On Fri, Dec 12, 2008 at 12:08 PM, Andrew Morton
<[email protected]> wrote:
> 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.
>>
>> 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

2008-12-12 06:37:45

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] clocksource: add enable() and disable() callbacks


* Magnus Damm <[email protected]> wrote:

> +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;

> @@ -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.

> + 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

2008-12-12 07:18:48

by Magnus Damm

[permalink] [raw]
Subject: Re: [PATCH] clocksource: add enable() and disable() callbacks

Hi Ingo,

On Fri, Dec 12, 2008 at 3:36 PM, Ingo Molnar <[email protected]> wrote:
> * Magnus Damm <[email protected]> wrote:
>> +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;

Sure, that's fine too.

>> @@ -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.

> 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.

>> + 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