* [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; 6+ messages in thread From: Colin Cross @ 2011-05-16 23:21 UTC (permalink / raw) To: linux-arm-kernel Cc: Colin Cross, Thomas Gleixner, Russell King, Santosh Shilimkar, Rob Herring, linux-arm-kernel, linux-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] 6+ messages in thread
* Re: [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; 6+ messages in thread From: Santosh Shilimkar @ 2011-05-17 14:00 UTC (permalink / raw) To: Colin Cross Cc: linux-arm-kernel, Thomas Gleixner, Russell King, Rob Herring, linux-arm-kernel, linux-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] 6+ messages in thread
* Re: [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; 6+ messages in thread From: Colin Cross @ 2011-05-17 17:06 UTC (permalink / raw) To: Santosh Shilimkar Cc: linux-arm-kernel, Thomas Gleixner, Russell King, Rob Herring, linux-arm-kernel, linux-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] 6+ messages in thread
* Re: [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; 6+ messages in thread From: Santosh Shilimkar @ 2011-05-18 11:32 UTC (permalink / raw) To: Colin Cross Cc: linux-arm-kernel, Thomas Gleixner, Russell King, Rob Herring, linux-arm-kernel, linux-kernel [-- Attachment #1: Type: text/plain, Size: 3405 bytes --] 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 [-- Attachment #2: 0001-OMAP4-clock-Add-CPU-local-timer-clock-node.patch --] [-- Type: text/plain, Size: 1577 bytes --] >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 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [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; 6+ messages in thread From: Linus Walleij @ 2011-05-19 17:32 UTC (permalink / raw) To: Colin Cross, Thomas Gleixner Cc: linux-arm-kernel, Russell King, linux-kernel, Santosh Shilimkar, linux-arm-kernel, Martin Persson, Rob Herring 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: >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> 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 related [flat|nested] 6+ messages in thread
* Re: [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; 6+ messages in thread From: Colin Cross @ 2011-05-19 23:26 UTC (permalink / raw) To: Linus Walleij Cc: Thomas Gleixner, linux-arm-kernel, Russell King, linux-kernel, Santosh Shilimkar, linux-arm-kernel, Martin Persson, Rob Herring 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] 6+ messages in thread
end of thread, other threads:[~2011-05-19 23:26 UTC | newest] Thread overview: 6+ 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
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).