* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
@ 2011-05-16 23:21 Colin Cross
2011-05-17 14:00 ` Santosh Shilimkar
2011-05-19 17:32 ` Linus Walleij
0 siblings, 2 replies; 11+ messages in thread
From: Colin Cross @ 2011-05-16 23:21 UTC (permalink / raw)
To: linux-arm-kernel
The localtimer's clock changes with the cpu clock. After a
cpufreq transition, update the clockevent's frequency and
reprogram the next clock event.
Adds a clock called "smp_twd" that is used to determine the
twd frequency, which can also be used at init time to
avoid calibrating the twd frequency.
Signed-off-by: Colin Cross <ccross@android.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Rob Herring <robherring2@gmail.com>
---
arch/arm/kernel/smp_twd.c | 69 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 66 insertions(+), 3 deletions(-)
This patch depends on Thomas Gleixner's patch to add clockevents_reconfigure
See: https://lkml.org/lkml/2011/5/13/122
This patch adds a clock that can be used to skip calibration as well
as update the frequency. A later patch (or a later version of this patch)
will drop twd_calibrate_rate once all platforms provide the necessary
smp_twd clock.
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 60636f4..dbf58d4 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -10,21 +10,29 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/percpu.h>
#include <asm/smp_twd.h>
#include <asm/hardware/gic.h>
+#define TWD_MIN_RANGE 4
+
/* set up by the platform code */
void __iomem *twd_base;
+static struct clk *twd_clk;
static unsigned long twd_timer_rate;
+static DEFINE_PER_CPU(struct clock_event_device *, twd_ce);
static void twd_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
@@ -80,6 +88,49 @@ int twd_timer_ack(void)
return 0;
}
+/*
+ * Updates clockevent frequency when the cpu frequency changes.
+ * Called on the cpu that is changing frequency with interrupts disabled.
+ */
+static void twd_update_frequency(void *data)
+{
+ twd_timer_rate = clk_get_rate(twd_clk);
+
+ clockevents_reconfigure(__get_cpu_var(twd_ce), twd_timer_rate,
+ TWD_MIN_RANGE);
+}
+
+static int twd_cpufreq_transition(struct notifier_block *nb,
+ unsigned long state, void *data)
+{
+ struct cpufreq_freqs *freqs = data;
+
+ /*
+ * The twd clock events must be reprogrammed to account for the new
+ * frequency. The timer is local to a cpu, so cross-call to the
+ * changing cpu.
+ */
+ if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
+ smp_call_function_single(freqs->cpu, twd_update_frequency,
+ NULL, 1);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block twd_cpufreq_nb = {
+ .notifier_call = twd_cpufreq_transition,
+};
+
+static int twd_cpufreq_init(void)
+{
+ if (!IS_ERR_OR_NULL(twd_clk))
+ return cpufreq_register_notifier(&twd_cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ return 0;
+}
+core_initcall(twd_cpufreq_init);
+
static void __cpuinit twd_calibrate_rate(void)
{
unsigned long count;
@@ -124,7 +175,16 @@ static void __cpuinit twd_calibrate_rate(void)
*/
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
{
- twd_calibrate_rate();
+ if (twd_clk == NULL) {
+ twd_clk = clk_get_sys("smp_twd", NULL);
+ if (IS_ERR_OR_NULL(twd_clk))
+ pr_warn("%s: no clock found\n", __func__);
+ }
+
+ if (!IS_ERR_OR_NULL(twd_clk))
+ twd_timer_rate = clk_get_rate(twd_clk);
+ else
+ twd_calibrate_rate();
clk->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
@@ -132,13 +192,16 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
clk->rating = 350;
clk->set_mode = twd_set_mode;
clk->set_next_event = twd_set_next_event;
- clk->shift = 20;
- clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
+
+ clockevents_calc_mult_shift(clk, twd_timer_rate, TWD_MIN_RANGE);
+
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
/* Make sure our local interrupt controller has this enabled */
gic_enable_ppi(clk->irq);
+ __get_cpu_var(twd_ce) = clk;
+
clockevents_register_device(clk);
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-05-16 23:21 [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change Colin Cross
@ 2011-05-17 14:00 ` Santosh Shilimkar
2011-05-17 17:06 ` Colin Cross
2011-05-19 17:32 ` Linus Walleij
1 sibling, 1 reply; 11+ messages in thread
From: Santosh Shilimkar @ 2011-05-17 14:00 UTC (permalink / raw)
To: linux-arm-kernel
Colin,
On 5/17/2011 4:51 AM, Colin Cross wrote:
> The localtimer's clock changes with the cpu clock. After a
> cpufreq transition, update the clockevent's frequency and
> reprogram the next clock event.
>
> Adds a clock called "smp_twd" that is used to determine the
> twd frequency, which can also be used at init time to
> avoid calibrating the twd frequency.
>
> Signed-off-by: Colin Cross<ccross@android.com>
> Cc: Thomas Gleixner<tglx@linutronix.de>
> Cc: Russell King<linux@arm.linux.org.uk>
> Cc: Santosh Shilimkar<santosh.shilimkar@ti.com>
> Cc: Rob Herring<robherring2@gmail.com>
> ---
> arch/arm/kernel/smp_twd.c | 69 +++++++++++++++++++++++++++++++++++++++++++--
> 1 files changed, 66 insertions(+), 3 deletions(-)
>
> This patch depends on Thomas Gleixner's patch to add clockevents_reconfigure
> See: https://lkml.org/lkml/2011/5/13/122
>
> This patch adds a clock that can be used to skip calibration as well
> as update the frequency. A later patch (or a later version of this patch)
> will drop twd_calibrate_rate once all platforms provide the necessary
> smp_twd clock.
>
Since the "smp_twd" clock node will not have a clk_set_rate()
associated with it, will the clk_get_rate() gives you real
rate. May be we can associate this node as a child of
CPU clock node and use the fixed divider based on peripheral
ratio. Is that the idea here to realize it ?
Regards,
Santosh
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-05-17 14:00 ` Santosh Shilimkar
@ 2011-05-17 17:06 ` Colin Cross
2011-05-18 11:32 ` Santosh Shilimkar
0 siblings, 1 reply; 11+ messages in thread
From: Colin Cross @ 2011-05-17 17:06 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, May 17, 2011 at 7:00 AM, Santosh Shilimkar
<santosh.shilimkar@ti.com> wrote:
> Colin,
>
> On 5/17/2011 4:51 AM, Colin Cross wrote:
>>
>> The localtimer's clock changes with the cpu clock. ?After a
>> cpufreq transition, update the clockevent's frequency and
>> reprogram the next clock event.
>>
>> Adds a clock called "smp_twd" that is used to determine the
>> twd frequency, which can also be used at init time to
>> avoid calibrating the twd frequency.
>>
>> Signed-off-by: Colin Cross<ccross@android.com>
>> Cc: Thomas Gleixner<tglx@linutronix.de>
>> Cc: Russell King<linux@arm.linux.org.uk>
>> Cc: Santosh Shilimkar<santosh.shilimkar@ti.com>
>> Cc: Rob Herring<robherring2@gmail.com>
>> ---
>> ?arch/arm/kernel/smp_twd.c | ? 69
>> +++++++++++++++++++++++++++++++++++++++++++--
>> ?1 files changed, 66 insertions(+), 3 deletions(-)
>>
>> This patch depends on Thomas Gleixner's patch to add
>> clockevents_reconfigure
>> See: https://lkml.org/lkml/2011/5/13/122
>>
>> This patch adds a clock that can be used to skip calibration as well
>> as update the frequency. ?A later patch (or a later version of this patch)
>> will drop twd_calibrate_rate once all platforms provide the necessary
>> smp_twd clock.
>>
>
> Since the "smp_twd" clock node will not have a clk_set_rate()
> associated with it, will the clk_get_rate() gives you real
> rate. May be we can associate this node as a child of
> CPU clock node and use the fixed divider based on peripheral
> ratio. Is that the idea here to realize it ?
Yes, the idea is that it will be a fixed divider off the cpu clock,
which will have been updated by cpufreq.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-05-17 17:06 ` Colin Cross
@ 2011-05-18 11:32 ` Santosh Shilimkar
0 siblings, 0 replies; 11+ messages in thread
From: Santosh Shilimkar @ 2011-05-18 11:32 UTC (permalink / raw)
To: linux-arm-kernel
On 5/17/2011 10:36 PM, Colin Cross wrote:
> On Tue, May 17, 2011 at 7:00 AM, Santosh Shilimkar
> <santosh.shilimkar@ti.com> wrote:
>> Colin,
>>
>> On 5/17/2011 4:51 AM, Colin Cross wrote:
>>>
>>> The localtimer's clock changes with the cpu clock. After a
>>> cpufreq transition, update the clockevent's frequency and
>>> reprogram the next clock event.
>>>
>>> Adds a clock called "smp_twd" that is used to determine the
>>> twd frequency, which can also be used at init time to
>>> avoid calibrating the twd frequency.
>>>
>>> Signed-off-by: Colin Cross<ccross@android.com>
>>> Cc: Thomas Gleixner<tglx@linutronix.de>
>>> Cc: Russell King<linux@arm.linux.org.uk>
>>> Cc: Santosh Shilimkar<santosh.shilimkar@ti.com>
>>> Cc: Rob Herring<robherring2@gmail.com>
>>> ---
>>> arch/arm/kernel/smp_twd.c | 69
>>> +++++++++++++++++++++++++++++++++++++++++++--
>>> 1 files changed, 66 insertions(+), 3 deletions(-)
>>>
>>> This patch depends on Thomas Gleixner's patch to add
>>> clockevents_reconfigure
>>> See: https://lkml.org/lkml/2011/5/13/122
>>>
>>> This patch adds a clock that can be used to skip calibration as well
>>> as update the frequency. A later patch (or a later version of this patch)
>>> will drop twd_calibrate_rate once all platforms provide the necessary
>>> smp_twd clock.
>>>
>>
>> Since the "smp_twd" clock node will not have a clk_set_rate()
>> associated with it, will the clk_get_rate() gives you real
>> rate. May be we can associate this node as a child of
>> CPU clock node and use the fixed divider based on peripheral
>> ratio. Is that the idea here to realize it ?
>
> Yes, the idea is that it will be a fixed divider off the cpu clock,
> which will have been updated by cpufreq.
Ok.
Below patch for OMAP twd clock node. Also
attached in case mailer eats tabs.
Regards
Santosh
From 8a3e307c1a610a24f78d575c0ac04a7bbe1d39b8 Mon Sep 17 00:00:00 2001
From: Santosh Shilimkar <santosh.shilimkar@ti.com>
Date: Wed, 18 May 2011 16:27:41 +0530
Subject: [PATCH] OMAP4: clock: Add CPU local timer clock node.
Local timer clock is sourced from the CPU clock and hence changes
along with CPU clock. These per CPU local timers are used as
clock-events, so they need to be reconfigured on CPU frequency
as part of CPUfreq governor.
Newly introduced clockevents_reconfigure() needs to know the
TWD clock-rate. Provide a clock-node to make clk_get_rate() work
for TWD.
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
arch/arm/mach-omap2/clock44xx_data.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/clock44xx_data.c
b/arch/arm/mach-omap2/clock44xx_data.c
index 8c96567..5477f4b 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3010,6 +3010,14 @@ static struct clk auxclkreq5_ck = {
.recalc = &omap2_clksel_recalc,
};
+static struct clk smp_twd = {
+ .name = "smp_twd",
+ .parent = &dpll_mpu_ck,
+ .ops = &clkops_null,
+ .fixed_div = 2,
+ .recalc = &omap_fixed_divisor_recalc,
+};
+
/*
* clkdev
*/
@@ -3283,6 +3291,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "auxclkreq3_ck", &auxclkreq3_ck, CK_443X),
CLK(NULL, "auxclkreq4_ck", &auxclkreq4_ck, CK_443X),
CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck, CK_443X),
+ CLK(NULL, "smp_twd", &smp_twd, CK_443X),
};
int __init omap4xxx_clk_init(void)
--
1.6.0.4
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 0001-OMAP4-clock-Add-CPU-local-timer-clock-node.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110518/d66dfefa/attachment-0001.ksh>
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-05-16 23:21 [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change Colin Cross
2011-05-17 14:00 ` Santosh Shilimkar
@ 2011-05-19 17:32 ` Linus Walleij
2011-05-19 23:26 ` Colin Cross
1 sibling, 1 reply; 11+ messages in thread
From: Linus Walleij @ 2011-05-19 17:32 UTC (permalink / raw)
To: linux-arm-kernel
2011/5/17 Colin Cross <ccross@android.com>:
> This patch depends on Thomas Gleixner's patch to add clockevents_reconfigure
> See: https://lkml.org/lkml/2011/5/13/122
Patch set has evolved, see below.
Also note that you more or less reimplement Rob Herrings patch:
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=6802/1
(no big deal I guess, give him a nod)
To work with Thomas full changeset just create a fresh branch and:
git pull git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-tip.git
timers/clockevents
Pls change subject from ARM: to clockevents: and merge through
Thomas tree (IMHO).
> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
> index 60636f4..dbf58d4 100644
> --- a/arch/arm/kernel/smp_twd.c
> +++ b/arch/arm/kernel/smp_twd.c
> @@ -10,21 +10,29 @@
> ?*/
> ?#include <linux/init.h>
> ?#include <linux/kernel.h>
> +#include <linux/clk.h>
> +#include <linux/cpufreq.h>
> ?#include <linux/delay.h>
> ?#include <linux/device.h>
> +#include <linux/err.h>
> ?#include <linux/smp.h>
> ?#include <linux/jiffies.h>
> ?#include <linux/clockchips.h>
> ?#include <linux/irq.h>
> ?#include <linux/io.h>
> +#include <linux/percpu.h>
>
> ?#include <asm/smp_twd.h>
> ?#include <asm/hardware/gic.h>
>
> +#define TWD_MIN_RANGE 4
> +
Loose this. Let the framework decide using the function below.
> ?/* set up by the platform code */
> ?void __iomem *twd_base;
>
> +static struct clk *twd_clk;
> ?static unsigned long twd_timer_rate;
> +static DEFINE_PER_CPU(struct clock_event_device *, twd_ce);
>
> ?static void twd_set_mode(enum clock_event_mode mode,
> ? ? ? ? ? ? ? ? ? ? ? ?struct clock_event_device *clk)
> @@ -80,6 +88,49 @@ int twd_timer_ack(void)
> ? ? ? ?return 0;
> ?}
>
> +/*
> + * Updates clockevent frequency when the cpu frequency changes.
> + * Called on the cpu that is changing frequency with interrupts disabled.
> + */
> +static void twd_update_frequency(void *data)
> +{
> + ? ? ? twd_timer_rate = clk_get_rate(twd_clk);
> +
> + ? ? ? clockevents_reconfigure(__get_cpu_var(twd_ce), twd_timer_rate,
> + ? ? ? ? ? ? ? ? ? ? ? TWD_MIN_RANGE);
Changed name to clockevents_update_freq(), dropped range argument.
> +}
> +
> +static int twd_cpufreq_transition(struct notifier_block *nb,
> + ? ? ? unsigned long state, void *data)
> +{
> + ? ? ? struct cpufreq_freqs *freqs = data;
> +
> + ? ? ? /*
> + ? ? ? ?* The twd clock events must be reprogrammed to account for the new
> + ? ? ? ?* frequency. ?The timer is local to a cpu, so cross-call to the
> + ? ? ? ?* changing cpu.
> + ? ? ? ?*/
> + ? ? ? if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
> + ? ? ? ? ? ? ? smp_call_function_single(freqs->cpu, twd_update_frequency,
> + ? ? ? ? ? ? ? ? ? ? ? NULL, 1);
> +
> + ? ? ? return NOTIFY_OK;
> +}
> +
> +static struct notifier_block twd_cpufreq_nb = {
> + ? ? ? .notifier_call = twd_cpufreq_transition,
> +};
> +
> +static int twd_cpufreq_init(void)
> +{
> + ? ? ? if (!IS_ERR_OR_NULL(twd_clk))
> + ? ? ? ? ? ? ? return cpufreq_register_notifier(&twd_cpufreq_nb,
> + ? ? ? ? ? ? ? ? ? ? ? CPUFREQ_TRANSITION_NOTIFIER);
> +
> + ? ? ? return 0;
> +}
> +core_initcall(twd_cpufreq_init);
> +
> ?static void __cpuinit twd_calibrate_rate(void)
> ?{
> ? ? ? ?unsigned long count;
> @@ -124,7 +175,16 @@ static void __cpuinit twd_calibrate_rate(void)
> ?*/
> ?void __cpuinit twd_timer_setup(struct clock_event_device *clk)
> ?{
> - ? ? ? twd_calibrate_rate();
> + ? ? ? if (twd_clk == NULL) {
> + ? ? ? ? ? ? ? twd_clk = clk_get_sys("smp_twd", NULL);
> + ? ? ? ? ? ? ? if (IS_ERR_OR_NULL(twd_clk))
> + ? ? ? ? ? ? ? ? ? ? ? pr_warn("%s: no clock found\n", __func__);
> + ? ? ? }
> +
> + ? ? ? if (!IS_ERR_OR_NULL(twd_clk))
> + ? ? ? ? ? ? ? twd_timer_rate = clk_get_rate(twd_clk);
> + ? ? ? else
> + ? ? ? ? ? ? ? twd_calibrate_rate();
>
> ? ? ? ?clk->name = "local_timer";
> ? ? ? ?clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
> @@ -132,13 +192,16 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
> ? ? ? ?clk->rating = 350;
> ? ? ? ?clk->set_mode = twd_set_mode;
> ? ? ? ?clk->set_next_event = twd_set_next_event;
> - ? ? ? clk->shift = 20;
> - ? ? ? clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
> +
> + ? ? ? clockevents_calc_mult_shift(clk, twd_timer_rate, TWD_MIN_RANGE);
> +
> ? ? ? ?clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
> ? ? ? ?clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
Get rid of everything between clk->shift ... and here and replace it with:
clockevents_config_and_register(clk, twd_timer_rate,
0xf, 0xffffffff);
> ? ? ? ?/* Make sure our local interrupt controller has this enabled */
> ? ? ? ?gic_enable_ppi(clk->irq);
>
> + ? ? ? __get_cpu_var(twd_ce) = clk;
> +
> ? ? ? ?clockevents_register_device(clk);
> ?}
Or just smack in this patch on top:
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-05-19 17:32 ` Linus Walleij
@ 2011-05-19 23:26 ` Colin Cross
0 siblings, 0 replies; 11+ messages in thread
From: Colin Cross @ 2011-05-19 23:26 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, May 19, 2011 at 10:32 AM, Linus Walleij
<linus.walleij@linaro.org> wrote:
> 2011/5/17 Colin Cross <ccross@android.com>:
>
>> This patch depends on Thomas Gleixner's patch to add clockevents_reconfigure
>> See: https://lkml.org/lkml/2011/5/13/122
>
> Patch set has evolved, see below.
> Also note that you more or less reimplement Rob Herrings patch:
> http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=6802/1
> (no big deal I guess, give him a nod)
>
> To work with Thomas full changeset just create a fresh branch and:
> git pull git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-tip.git
> timers/clockevents
>
> Pls change subject from ARM: to clockevents: and merge through
> Thomas tree (IMHO).
I don't think the subject should change - the patch is to ARM code,
not clockevent code, it's named for what the patch does, not whose
tree it goes through.
>> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
>> index 60636f4..dbf58d4 100644
>> --- a/arch/arm/kernel/smp_twd.c
>> +++ b/arch/arm/kernel/smp_twd.c
>> @@ -10,21 +10,29 @@
>> ?*/
>> ?#include <linux/init.h>
>> ?#include <linux/kernel.h>
>> +#include <linux/clk.h>
>> +#include <linux/cpufreq.h>
>> ?#include <linux/delay.h>
>> ?#include <linux/device.h>
>> +#include <linux/err.h>
>> ?#include <linux/smp.h>
>> ?#include <linux/jiffies.h>
>> ?#include <linux/clockchips.h>
>> ?#include <linux/irq.h>
>> ?#include <linux/io.h>
>> +#include <linux/percpu.h>
>>
>> ?#include <asm/smp_twd.h>
>> ?#include <asm/hardware/gic.h>
>>
>> +#define TWD_MIN_RANGE 4
>> +
>
> Loose this. Let the framework decide using the function below.
>
>> ?/* set up by the platform code */
>> ?void __iomem *twd_base;
>>
>> +static struct clk *twd_clk;
>> ?static unsigned long twd_timer_rate;
>> +static DEFINE_PER_CPU(struct clock_event_device *, twd_ce);
>>
>> ?static void twd_set_mode(enum clock_event_mode mode,
>> ? ? ? ? ? ? ? ? ? ? ? ?struct clock_event_device *clk)
>> @@ -80,6 +88,49 @@ int twd_timer_ack(void)
>> ? ? ? ?return 0;
>> ?}
>>
>> +/*
>> + * Updates clockevent frequency when the cpu frequency changes.
>> + * Called on the cpu that is changing frequency with interrupts disabled.
>> + */
>> +static void twd_update_frequency(void *data)
>> +{
>> + ? ? ? twd_timer_rate = clk_get_rate(twd_clk);
>> +
>> + ? ? ? clockevents_reconfigure(__get_cpu_var(twd_ce), twd_timer_rate,
>> + ? ? ? ? ? ? ? ? ? ? ? TWD_MIN_RANGE);
>
> Changed name to clockevents_update_freq(), dropped range argument.
>
>> +}
>> +
>> +static int twd_cpufreq_transition(struct notifier_block *nb,
>> + ? ? ? unsigned long state, void *data)
>> +{
>> + ? ? ? struct cpufreq_freqs *freqs = data;
>> +
>> + ? ? ? /*
>> + ? ? ? ?* The twd clock events must be reprogrammed to account for the new
>> + ? ? ? ?* frequency. ?The timer is local to a cpu, so cross-call to the
>> + ? ? ? ?* changing cpu.
>> + ? ? ? ?*/
>> + ? ? ? if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
>> + ? ? ? ? ? ? ? smp_call_function_single(freqs->cpu, twd_update_frequency,
>> + ? ? ? ? ? ? ? ? ? ? ? NULL, 1);
>> +
>> + ? ? ? return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block twd_cpufreq_nb = {
>> + ? ? ? .notifier_call = twd_cpufreq_transition,
>> +};
>> +
>> +static int twd_cpufreq_init(void)
>> +{
>> + ? ? ? if (!IS_ERR_OR_NULL(twd_clk))
>> + ? ? ? ? ? ? ? return cpufreq_register_notifier(&twd_cpufreq_nb,
>> + ? ? ? ? ? ? ? ? ? ? ? CPUFREQ_TRANSITION_NOTIFIER);
>> +
>> + ? ? ? return 0;
>> +}
>> +core_initcall(twd_cpufreq_init);
>> +
>> ?static void __cpuinit twd_calibrate_rate(void)
>> ?{
>> ? ? ? ?unsigned long count;
>> @@ -124,7 +175,16 @@ static void __cpuinit twd_calibrate_rate(void)
>> ?*/
>> ?void __cpuinit twd_timer_setup(struct clock_event_device *clk)
>> ?{
>> - ? ? ? twd_calibrate_rate();
>> + ? ? ? if (twd_clk == NULL) {
>> + ? ? ? ? ? ? ? twd_clk = clk_get_sys("smp_twd", NULL);
>> + ? ? ? ? ? ? ? if (IS_ERR_OR_NULL(twd_clk))
>> + ? ? ? ? ? ? ? ? ? ? ? pr_warn("%s: no clock found\n", __func__);
>> + ? ? ? }
>> +
>> + ? ? ? if (!IS_ERR_OR_NULL(twd_clk))
>> + ? ? ? ? ? ? ? twd_timer_rate = clk_get_rate(twd_clk);
>> + ? ? ? else
>> + ? ? ? ? ? ? ? twd_calibrate_rate();
>>
>> ? ? ? ?clk->name = "local_timer";
>> ? ? ? ?clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
>> @@ -132,13 +192,16 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
>> ? ? ? ?clk->rating = 350;
>> ? ? ? ?clk->set_mode = twd_set_mode;
>> ? ? ? ?clk->set_next_event = twd_set_next_event;
>> - ? ? ? clk->shift = 20;
>> - ? ? ? clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
>> +
>> + ? ? ? clockevents_calc_mult_shift(clk, twd_timer_rate, TWD_MIN_RANGE);
>> +
>> ? ? ? ?clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
>> ? ? ? ?clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
>
> Get rid of everything between clk->shift ... and here and replace it with:
>
> clockevents_config_and_register(clk, twd_timer_rate,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xf, 0xffffffff);
>
>> ? ? ? ?/* Make sure our local interrupt controller has this enabled */
>> ? ? ? ?gic_enable_ppi(clk->irq);
>>
>> + ? ? ? __get_cpu_var(twd_ce) = clk;
>> +
>> ? ? ? ?clockevents_register_device(clk);
>> ?}
>
>
> Or just smack in this patch on top:
>
> From fd546090b8f0cb5df06103c014466c86cf58b73a Mon Sep 17 00:00:00 2001
> From: Linus Walleij <linus.walleij@stericsson.com>
> Date: Thu, 19 May 2011 18:55:22 +0200
> Subject: [PATCH] Fix smallish cleanup
>
> ---
> ?arch/arm/kernel/smp_twd.c | ? 13 +++----------
> ?1 files changed, 3 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
> index dbf58d4..968f298 100644
> --- a/arch/arm/kernel/smp_twd.c
> +++ b/arch/arm/kernel/smp_twd.c
> @@ -25,8 +25,6 @@
> ?#include <asm/smp_twd.h>
> ?#include <asm/hardware/gic.h>
>
> -#define TWD_MIN_RANGE 4
> -
> ?/* set up by the platform code */
> ?void __iomem *twd_base;
>
> @@ -96,8 +94,7 @@ static void twd_update_frequency(void *data)
> ?{
> ? ? ? ?twd_timer_rate = clk_get_rate(twd_clk);
>
> - ? ? ? clockevents_reconfigure(__get_cpu_var(twd_ce), twd_timer_rate,
> - ? ? ? ? ? ? ? ? ? ? ? TWD_MIN_RANGE);
> + ? ? ? clockevents_update_freq(__get_cpu_var(twd_ce), twd_timer_rate);
> ?}
>
> ?static int twd_cpufreq_transition(struct notifier_block *nb,
> @@ -193,15 +190,11 @@ void __cpuinit twd_timer_setup(struct
> clock_event_device *clk)
> ? ? ? ?clk->set_mode = twd_set_mode;
> ? ? ? ?clk->set_next_event = twd_set_next_event;
>
> - ? ? ? clockevents_calc_mult_shift(clk, twd_timer_rate, TWD_MIN_RANGE);
> -
> - ? ? ? clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
> - ? ? ? clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
> -
> ? ? ? ?/* Make sure our local interrupt controller has this enabled */
> ? ? ? ?gic_enable_ppi(clk->irq);
>
> ? ? ? ?__get_cpu_var(twd_ce) = clk;
>
> - ? ? ? clockevents_register_device(clk);
> + ? ? ? clockevents_config_and_register(clk, twd_timer_rate,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0xf, 0xffffffff);
> ?}
> --
> 1.7.3.2
>
>
> With these changes (provided they work) all should be well, so:
> Tested-by: Linus Walleij <linus.walleij@linaro.org>
Thanks, I'll squash your fixes in.
> If all is well on your side as well, ask Thomas to take this into the
> timers/clockevents branch where all dependencies are.
>
> Yours,
> Linus Walleij
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
@ 2011-06-01 9:15 Linus Walleij
2011-06-14 5:50 ` Linus Walleij
0 siblings, 1 reply; 11+ messages in thread
From: Linus Walleij @ 2011-06-01 9:15 UTC (permalink / raw)
To: linux-arm-kernel
From: Colin Cross <ccross@android.com>
The localtimer's clock changes with the cpu clock. After a
cpufreq transition, update the clockevent's frequency and
reprogram the next clock event.
Adds a clock called "smp_twd" that is used to determine the
twd frequency, which can also be used at init time to
avoid calibrating the twd frequency.
Clock changes are based on Rob Herring's work.
Signed-off-by: Colin Cross <ccross@android.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Russell King <linux@arm.linux.org.uk>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[ifdef:ed CPUfreq stuff for non-cpufreq configs]
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
I'm sending this as a pull request to Russells in this form,
this nasty cpufreq bug which is making the system timeline
jump back and forth on ux500 is *certainly* -rc material to me,
but I'm leaving it for Russell to decide.
Tested with and without CPUfreq support.
---
arch/arm/kernel/smp_twd.c | 90 ++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 84 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 60636f4..5c8775d 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -10,13 +10,17 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/percpu.h>
#include <asm/smp_twd.h>
#include <asm/hardware/gic.h>
@@ -24,7 +28,9 @@
/* set up by the platform code */
void __iomem *twd_base;
+static struct clk *twd_clk;
static unsigned long twd_timer_rate;
+static DEFINE_PER_CPU(struct clock_event_device *, twd_ce);
static void twd_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
@@ -80,6 +86,52 @@ int twd_timer_ack(void)
return 0;
}
+#ifdef CONFIG_CPU_FREQ
+
+/*
+ * Updates clockevent frequency when the cpu frequency changes.
+ * Called on the cpu that is changing frequency with interrupts disabled.
+ */
+static void twd_update_frequency(void *data)
+{
+ twd_timer_rate = clk_get_rate(twd_clk);
+
+ clockevents_update_freq(__get_cpu_var(twd_ce), twd_timer_rate);
+}
+
+static int twd_cpufreq_transition(struct notifier_block *nb,
+ unsigned long state, void *data)
+{
+ struct cpufreq_freqs *freqs = data;
+
+ /*
+ * The twd clock events must be reprogrammed to account for the new
+ * frequency. The timer is local to a cpu, so cross-call to the
+ * changing cpu.
+ */
+ if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
+ smp_call_function_single(freqs->cpu, twd_update_frequency,
+ NULL, 1);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block twd_cpufreq_nb = {
+ .notifier_call = twd_cpufreq_transition,
+};
+
+static int twd_cpufreq_init(void)
+{
+ if (!IS_ERR_OR_NULL(twd_clk))
+ return cpufreq_register_notifier(&twd_cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ return 0;
+}
+core_initcall(twd_cpufreq_init);
+
+#endif
+
static void __cpuinit twd_calibrate_rate(void)
{
unsigned long count;
@@ -119,12 +171,39 @@ static void __cpuinit twd_calibrate_rate(void)
}
}
+static struct clk *twd_get_clock(void)
+{
+ struct clk *clk;
+ int err;
+
+ clk = clk_get_sys("smp_twd", NULL);
+ if (IS_ERR(clk)) {
+ pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
+ return clk;
+ }
+
+ err = clk_enable(clk);
+ if (err) {
+ pr_err("smp_twd: clock failed to enable: %d\n", err);
+ clk_put(clk);
+ return ERR_PTR(err);
+ }
+
+ return clk;
+}
+
/*
* Setup the local clock events for a CPU.
*/
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
{
- twd_calibrate_rate();
+ if (!twd_clk)
+ twd_clk = twd_get_clock();
+
+ if (!IS_ERR_OR_NULL(twd_clk))
+ twd_timer_rate = clk_get_rate(twd_clk);
+ else
+ twd_calibrate_rate();
clk->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
@@ -132,13 +211,12 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
clk->rating = 350;
clk->set_mode = twd_set_mode;
clk->set_next_event = twd_set_next_event;
- clk->shift = 20;
- clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
- clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
- clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
/* Make sure our local interrupt controller has this enabled */
gic_enable_ppi(clk->irq);
- clockevents_register_device(clk);
+ __get_cpu_var(twd_ce) = clk;
+
+ clockevents_config_and_register(clk, twd_timer_rate,
+ 0xf, 0xffffffff);
}
--
1.7.3.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-06-01 9:15 Linus Walleij
@ 2011-06-14 5:50 ` Linus Walleij
2011-06-14 6:00 ` Colin Cross
0 siblings, 1 reply; 11+ messages in thread
From: Linus Walleij @ 2011-06-14 5:50 UTC (permalink / raw)
To: linux-arm-kernel
Colin, Per Fransson noted this:
> From: Colin Cross <ccross@android.com>
> +/*
> + * Updates clockevent frequency when the cpu frequency changes.
> + * Called on the cpu that is changing frequency with interrupts disabled.
> + */
> +static void twd_update_frequency(void *data)
> +{
> + ? ? ? twd_timer_rate = clk_get_rate(twd_clk);
> +
> + ? ? ? clockevents_update_freq(__get_cpu_var(twd_ce), twd_timer_rate);
> +}
Will only update the clockevent on the CPU where the cpufreq notifier
gets called will it not? It's not called on each CPU AFAICT.
So this function has to traverse all CPUs in twd_ce.
Thanks,
Linus Walleij
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-06-14 5:50 ` Linus Walleij
@ 2011-06-14 6:00 ` Colin Cross
2011-06-14 6:12 ` Santosh Shilimkar
0 siblings, 1 reply; 11+ messages in thread
From: Colin Cross @ 2011-06-14 6:00 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jun 13, 2011 at 10:50 PM, Linus Walleij
<linus.ml.walleij@gmail.com> wrote:
> Colin, Per Fransson noted this:
>
>> From: Colin Cross <ccross@android.com>
>
>> +/*
>> + * Updates clockevent frequency when the cpu frequency changes.
>> + * Called on the cpu that is changing frequency with interrupts disabled.
>> + */
>> +static void twd_update_frequency(void *data)
>> +{
>> + ? ? ? twd_timer_rate = clk_get_rate(twd_clk);
>> +
>> + ? ? ? clockevents_update_freq(__get_cpu_var(twd_ce), twd_timer_rate);
>> +}
>
> Will only update the clockevent on the CPU where the cpufreq notifier
> gets called will it not? It's not called on each CPU AFAICT.
>
> So this function has to traverse all CPUs in twd_ce.
OMAP and Tegra both iterate through all the affected cpus in the
cpufreq driver and call cpufreq_notify_transtion once for each,
setting freqs.cpu to the target cpu. The listener in the smp_twd
driver then bounces through smp_call_function_single to make sure it
is running on the affected cpu. I believe that is the correct way to
handle multiple affected cpus.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-06-14 6:00 ` Colin Cross
@ 2011-06-14 6:12 ` Santosh Shilimkar
2011-06-14 6:14 ` Linus Walleij
0 siblings, 1 reply; 11+ messages in thread
From: Santosh Shilimkar @ 2011-06-14 6:12 UTC (permalink / raw)
To: linux-arm-kernel
On 6/14/2011 11:30 AM, Colin Cross wrote:
> On Mon, Jun 13, 2011 at 10:50 PM, Linus Walleij
> <linus.ml.walleij@gmail.com> wrote:
>> Colin, Per Fransson noted this:
>>
>>> From: Colin Cross<ccross@android.com>
>>
>>> +/*
>>> + * Updates clockevent frequency when the cpu frequency changes.
>>> + * Called on the cpu that is changing frequency with interrupts disabled.
>>> + */
>>> +static void twd_update_frequency(void *data)
>>> +{
>>> + twd_timer_rate = clk_get_rate(twd_clk);
>>> +
>>> + clockevents_update_freq(__get_cpu_var(twd_ce), twd_timer_rate);
>>> +}
>>
>> Will only update the clockevent on the CPU where the cpufreq notifier
>> gets called will it not? It's not called on each CPU AFAICT.
>>
>> So this function has to traverse all CPUs in twd_ce.
>
> OMAP and Tegra both iterate through all the affected cpus in the
> cpufreq driver and call cpufreq_notify_transtion once for each,
> setting freqs.cpu to the target cpu. The listener in the smp_twd
> driver then bounces through smp_call_function_single to make sure it
> is running on the affected cpu. I believe that is the correct way to
> handle multiple affected cpus.
>
I agree with Collin. That should be taken care by
"smp_call_function_single(freqs->cpu, )" with notifier
being called with all the available CPU's in the mask.
Linus,
Did you see any issue with this patch on your platform ?
Regards
Santosh
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change
2011-06-14 6:12 ` Santosh Shilimkar
@ 2011-06-14 6:14 ` Linus Walleij
0 siblings, 0 replies; 11+ messages in thread
From: Linus Walleij @ 2011-06-14 6:14 UTC (permalink / raw)
To: linux-arm-kernel
2011/6/14 Santosh Shilimkar <santosh.shilimkar@ti.com>:
> That should be taken care by
> "smp_call_function_single(freqs->cpu, )" with notifier
> being called with all the available CPU's in the mask.
Ah! I see now.
> Did you see any issue with this patch on your platform ?
No, I don't think so, I think we saw the problem on an
earlier version that didn't use smp_call_function_single().
Thanks,
Linus Walleij
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2011-06-14 6:14 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-16 23:21 [PATCH] ARM: smp_twd: Reconfigure clockevents after cpufreq change Colin Cross
2011-05-17 14:00 ` Santosh Shilimkar
2011-05-17 17:06 ` Colin Cross
2011-05-18 11:32 ` Santosh Shilimkar
2011-05-19 17:32 ` Linus Walleij
2011-05-19 23:26 ` Colin Cross
-- strict thread matches above, loose matches on Subject: below --
2011-06-01 9:15 Linus Walleij
2011-06-14 5:50 ` Linus Walleij
2011-06-14 6:00 ` Colin Cross
2011-06-14 6:12 ` Santosh Shilimkar
2011-06-14 6:14 ` Linus Walleij
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).