ARM: sched_clock: allow sched_clock to be selected at runtime
Subsystems (10)
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
sched_clock() is yet another blocker on the road to the single image. This patch implements an idea by Russell King:
http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both sched_clock() itself and the rollover callback, simply register a read() function, and let the ARM code care about sched_clock() itself, the conversion to ns and the rollover. sched_clock() uses this read() function as an indirection to the platform code.
This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the *_fixed_sched_clock optimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).
Tested on 11MPCore, OMAP4 and Tegra.
---
Based on v3.0-rc1.
arch/arm/include/asm/sched_clock.h | 108 +----------------------------- arch/arm/kernel/sched_clock.c | 97 +++++++++++++++++++++++++-- arch/arm/mach-ixp4xx/common.c | 15 +--- arch/arm/mach-mmp/time.c | 15 +--- arch/arm/mach-omap1/time.c | 57 +--------------- arch/arm/mach-omap2/timer.c | 20 +----- arch/arm/mach-pxa/time.c | 14 +--- arch/arm/mach-sa1100/time.c | 27 +------- arch/arm/mach-tegra/timer.c | 23 +------ arch/arm/mach-u300/timer.c | 14 +--- arch/arm/plat-iop/time.c | 15 +--- arch/arm/plat-mxc/time.c | 15 +--- arch/arm/plat-nomadik/timer.c | 17 +---- arch/arm/plat-omap/counter_32k.c | 39 +---------- arch/arm/plat-omap/include/plat/common.h | 2 +- arch/arm/plat-orion/time.c | 20 +----- arch/arm/plat-s5p/s5p-time.c | 18 +---- arch/arm/plat-versatile/sched-clock.c | 27 ++------ 18 files changed, 141 insertions(+), 402 deletions(-)
arch/arm/include/asm/sched_clock.h +1 -107
@@ -8,113 +8,7 @@#ifndef ASM_SCHED_CLOCK #define ASM_SCHED_CLOCK -#include <linux/kernel.h> -#include <linux/types.h> - -struct clock_data { -u64 epoch_ns; -u32 epoch_cyc; -u32 epoch_cyc_copy; -u32 mult; -u32 shift; -}; - -#define DEFINE_CLOCK_DATA (name) struct clock_data name - -static inline u64 cyc_to_ns (u64 cyc,u32 mult,u32 shift) -{ -return (cyc * mult) >> shift; -} - -/* -* Atomically update the sched_clock epoch. Your update callback will -* be called from a timer before the counter wraps - read the current -* counter value, and call this function to safely move the epochs -* forward. Only use this from the update callback. -*/ -static inline void update_sched_clock (struct clock_data *cd,u32 cyc,u32 mask) -{ -unsigned long flags; -u64 ns = cd->epoch_ns + -cyc_to_ns ((cyc - cd->epoch_cyc) & mask, cd->mult, cd->shift); - -/* -* Write epoch_cyc and epoch_ns in a way that the update is -* detectable in cyc_to_fixed_sched_clock(). -*/ -raw_local_irq_save (flags); - cd->epoch_cyc = cyc; -smp_wmb (); - cd->epoch_ns = ns; -smp_wmb (); - cd->epoch_cyc_copy = cyc; -raw_local_irq_restore (flags); -} - -/* -* If your clock rate is known at compile time, using this will allow -* you to optimize the mult/shift loads away. This is paired with -* init_fixed_sched_clock() to ensure that your mult/shift are correct. -*/ -static inline unsigned long long cyc_to_fixed_sched_clock (struct clock_data *cd, -u32 cyc,u32 mask,u32 mult,u32 shift) -{ -u64 epoch_ns; -u32 epoch_cyc; - -/* -* Load the epoch_cyc and epoch_ns atomically. We do this by -* ensuring that we always write epoch_cyc, epoch_ns and -* epoch_cyc_copy in strict order, and read them in strict order. -* If epoch_cyc and epoch_cyc_copy are not equal, then we're in -* the middle of an update, and we should repeat the load. -*/ -do { - epoch_cyc = cd->epoch_cyc; -smp_rmb (); - epoch_ns = cd->epoch_ns; -smp_rmb (); - }while (epoch_cyc != cd->epoch_cyc_copy); - -return epoch_ns +cyc_to_ns ((cyc - epoch_cyc) & mask, mult, shift); -} - -/* -* Otherwise, you need to use this, which will obtain the mult/shift -* from the clock_data structure. Use init_sched_clock() with this. -*/ -static inline unsigned long long cyc_to_sched_clock (struct clock_data *cd, -u32 cyc,u32 mask) -{ -return cyc_to_fixed_sched_clock (cd, cyc, mask, cd->mult, cd->shift); -} - -/* -* Initialize the clock data - calculate the appropriate multiplier -* and shift. Also setup a timer to ensure that the epoch is refreshed -* at the appropriate time interval, which will call your update -* handler. -*/ -void init_sched_clock (struct clock_data *,void (*)(void ), -unsigned int ,unsigned long ); - -/* -* Use this initialization function rather than init_sched_clock() if -* you're using cyc_to_fixed_sched_clock, which will warn if your -* constants are incorrect. -*/ -static inline void init_fixed_sched_clock (struct clock_data *cd, -void (*update)(void ),unsigned int bits,unsigned long rate, -u32 mult,u32 shift) -{ -init_sched_clock (cd, update, bits, rate); -if (cd->mult != mult || cd->shift != shift) { -pr_crit ("sched_clock: wrong multiply/shift: %u>>%u vs calculated %u>>%u\n" -"sched_clock: fix multiply/shift to avoid scheduler hiccups\n" , - mult, shift, cd->mult, cd->shift); - } -} -extern void sched_clock_postinit (void ); +extern void setup_sched_clock (u32 (*read)(void ),int bits,unsigned long rate);#endif
arch/arm/kernel/sched_clock.c +90 -7
128 lines not on this page · raw message
arch/arm/mach-ixp4xx/common.c +3 -12
@@ -402,18 +402,9 @@ void __init ixp4xx_sys_init(void)/* * sched_clock() */ -static DEFINE_CLOCK_DATA (cd); - -unsigned long long notrace sched_clock (void ) +static u32 ixp4xx_read_sched_clock (void ) { -u32 cyc = *IXP4XX_OSTS ; -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace ixp4xx_update_sched_clock(void) -{ -u32 cyc = *IXP4XX_OSTS ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return *IXP4XX_OSTS ; }/*
@@ -429,7 +420,7 @@ unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;EXPORT_SYMBOL (ixp4xx_timer_freq);static void __init ixp4xx_clocksource_init (void ) { -init_sched_clock (&cd, ixp4xx_update_sched_clock,32 , ixp4xx_timer_freq); +setup_sched_clock (ixp4xx_read_sched_clock,32 , ixp4xx_timer_freq);clocksource_mmio_init (NULL ,"OSTS" , ixp4xx_timer_freq,200 ,32 , ixp4xx_clocksource_read);
arch/arm/mach-mmp/time.c +3 -12
@@ -42,8 +42,6 @@#define MAX_DELTA (0xfffffffe)#define MIN_DELTA (16) -static DEFINE_CLOCK_DATA (cd); -/* * FIXME: the timer needs some delay to stablize the counter capture */
@@ -59,16 +57,9 @@ static inline uint32_t timer_read(void)return __raw_readl (TIMERS_VIRT_BASE +TMR_CVWR (0 )); } -unsigned long long notrace sched_clock (void ) +static u32 mmp_read_sched_clock (void ) { -u32 cyc =timer_read (); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace mmp_update_sched_clock(void) -{ -u32 cyc =timer_read (); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return timer_read (); }static irqreturn_t timer_interrupt (int irq,void *dev_id)
@@ -175,7 +166,7 @@ void __init timer_init(int irq) {timer_config (); -init_sched_clock (&cd, mmp_update_sched_clock,32 ,CLOCK_TICK_RATE ); +setup_sched_clock (mmp_read_sched_clock,32 ,CLOCK_TICK_RATE ); ckevt.mult =div_sc (CLOCK_TICK_RATE ,NSEC_PER_SEC , ckevt.shift); ckevt.max_delta_ns =clockevent_delta2ns (MAX_DELTA , &ckevt);
arch/arm/mach-omap1/time.c +4 -53
83 lines not on this page · raw message
arch/arm/mach-omap2/timer.c +4 -16
@@ -248,7 +248,6 @@ static struct omap_dm_timer clksrc;/* * clocksource */ -static DEFINE_CLOCK_DATA (cd);static cycle_t clocksource_read_cycles (struct clocksource *cs) {return (cycle_t )__omap_dm_timer_read_counter (clksrc.io_base,1 );
@@ -262,23 +261,12 @@ static struct clocksource clocksource_gpt = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void notrace dmtimer_update_sched_clock(void) +static u32 dmtimer_read_sched_clock (void ) { -u32 cyc; - - cyc =__omap_dm_timer_read_counter (clksrc.io_base,1 ); - -update_sched_clock (&cd, cyc, (u32 )~0 ); -} - -unsigned long long notrace sched_clock (void ) -{ -u32 cyc =0 ; -if (clksrc.reserved) - cyc =__omap_dm_timer_read_counter (clksrc.io_base,1 ); +return __omap_dm_timer_read_counter (clksrc.io_base,1 ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); +return 0 ; }/* Setup free-running counter for clocksource */
@@ -294,7 +282,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, gptimer_id, clksrc.rate);__omap_dm_timer_load_start (clksrc.io_base,OMAP_TIMER_CTRL_ST ,0 ,1 ); -init_sched_clock (&cd, dmtimer_update_sched_clock,32 , clksrc.rate); +setup_sched_clock (dmtimer_read_sched_clock,32 , clksrc.rate);if (clocksource_register_hz (&clocksource_gpt, clksrc.rate)) pr_err("Could not register clocksource %s\n",
arch/arm/mach-pxa/time.c +3 -11
@@ -32,18 +32,10 @@* long as there is always less than 582 seconds between successive * calls to sched_clock() which should always be the case in practice. */ -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 pxa_read_sched_clock (void ) { -u32 cyc =OSCR ; -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace pxa_update_sched_clock(void) -{ -u32 cyc =OSCR ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return OSCR ; }
@@ -119,7 +111,7 @@ static void __init pxa_timer_init(void)OIER =0 ;OSSR =OSSR_M0 |OSSR_M1 |OSSR_M2 |OSSR_M3 ; -init_sched_clock (&cd, pxa_update_sched_clock,32 , clock_tick_rate); +setup_sched_clock (pxa_read_sched_clock,32 , clock_tick_rate);clockevents_calc_mult_shift (&ckevt_pxa_osmr0, clock_tick_rate,4 ); ckevt_pxa_osmr0.max_delta_ns =
arch/arm/mach-sa1100/time.c +3 -24
@@ -20,29 +20,9 @@#include <asm/sched_clock.h> #include <mach/hardware.h> -/* -* This is the SA11x0 sched_clock implementation. -*/ -static DEFINE_CLOCK_DATA (cd); - -/* -* Constants generated by clocks_calc_mult_shift(m, s, 3.6864MHz, -* NSEC_PER_SEC, 60). -* This gives a resolution of about 271ns and a wrap period of about 19min. -*/ -#define SC_MULT 2275555556u -#define SC_SHIFT 23 - -unsigned long long notrace sched_clock (void ) -{ -u32 cyc =OSCR ; -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 ,SC_MULT ,SC_SHIFT ); -} - -static void notrace sa1100_update_sched_clock(void) +static u32 sa100_read_sched_clock (void ) { -u32 cyc =OSCR ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return OSCR ; }#define MIN_OSCR_DELTA 2
@@ -109,8 +89,7 @@ static void __init sa1100_timer_init(void)OIER =0 ;OSSR =OSSR_M0 |OSSR_M1 |OSSR_M2 |OSSR_M3 ; -init_fixed_sched_clock (&cd, sa1100_update_sched_clock,32 , -3686400 ,SC_MULT ,SC_SHIFT ); +setup_sched_clock (sa1100_read_sched_clock,32 ,3686400 );clockevents_calc_mult_shift (&ckevt_sa1100_osmr0,3686400 ,4 ); ckevt_sa1100_osmr0.max_delta_ns =
arch/arm/mach-tegra/timer.c +3 -20
@@ -106,25 +106,9 @@ static struct clock_event_device tegra_clockevent = { .set_mode = tegra_timer_set_mode, }; -static DEFINE_CLOCK_DATA (cd); - -/* -* Constants generated by clocks_calc_mult_shift(m, s, 1MHz, NSEC_PER_SEC, 60). -* This gives a resolution of about 1us and a wrap period of about 1h11min. -*/ -#define SC_MULT 4194304000u -#define SC_SHIFT 22 - -unsigned long long notrace sched_clock (void ) -{ -u32 cyc =timer_readl (TIMERUS_CNTR_1US ); -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 ,SC_MULT ,SC_SHIFT ); -} - -static void notrace tegra_update_sched_clock(void) +static u32 tegra_read_sched_clock (void ) { -u32 cyc =timer_readl (TIMERUS_CNTR_1US ); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return timer_readl (TIMERUS_CNTR_1US ); }/*
@@ -218,8 +202,7 @@ static void __init tegra_init_timer(void)WARN (1 ,"Unknown clock rate" ); } -init_fixed_sched_clock (&cd, tegra_update_sched_clock,32 , -1000000 ,SC_MULT ,SC_SHIFT ); +setup_sched_clock (tegra_read_sched_clock,32 ,1000000 );if (clocksource_mmio_init (timer_reg_base +TIMERUS_CNTR_1US ,"timer_us" ,1000000 ,300 ,32 , clocksource_mmio_readl_up)) {
arch/arm/mach-u300/timer.c +3 -11
@@ -337,18 +337,10 @@ static struct irqaction u300_timer_irq = {* this wraps around for now, since it is just a relative time * stamp. (Inspired by OMAP implementation.) */ -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 u300_read_sched_clock (void ) { -u32 cyc =readl (U300_TIMER_APP_VBASE +U300_TIMER_APP_GPT2CC ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace u300_update_sched_clock(void) -{ -u32 cyc =readl (U300_TIMER_APP_VBASE +U300_TIMER_APP_GPT2CC ); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return readl (U300_TIMER_APP_VBASE +U300_TIMER_APP_GPT2CC ); }
@@ -366,7 +358,7 @@ static void __init u300_timer_init(void)clk_enable (clk); rate =clk_get_rate (clk); -init_sched_clock (&cd, u300_update_sched_clock,32 , rate); +setup_sched_clock (u300_read_sched_clock,32 , rate);/* * Disable the "OS" and "DD" timers - these are designed for Symbian!
arch/arm/plat-iop/time.c +3 -12
@@ -51,21 +51,12 @@ static struct clocksource iop_clocksource = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static DEFINE_CLOCK_DATA (cd); -/* * IOP sched_clock() implementation via its clocksource. */ -unsigned long long notrace sched_clock (void ) +static u32 iop_read_sched_clock (void ) { -u32 cyc =0xffffffffu -read_tcr1 (); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace iop_update_sched_clock(void) -{ -u32 cyc =0xffffffffu -read_tcr1 (); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return 0xffffffffu -read_tcr1 (); }/*
@@ -151,7 +142,7 @@ void __init iop_init_time(unsigned long tick_rate) {u32 timer_ctl; -init_sched_clock (&cd, iop_update_sched_clock,32 , tick_rate); +setup_sched_clock (iop_read_sched_clock,32 , tick_rate); ticks_per_jiffy =DIV_ROUND_CLOSEST (tick_rate,HZ ); iop_tick_rate = tick_rate;
arch/arm/plat-mxc/time.c +3 -12
@@ -108,18 +108,9 @@ static void gpt_irq_acknowledge(void)static void __iomem *sched_clock_reg; -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 mxc_read_sched_clock (void ) { -cycle_t cyc = sched_clock_reg ?__raw_readl (sched_clock_reg) :0 ; - -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace mxc_update_sched_clock(void) -{ -cycle_t cyc = sched_clock_reg ?__raw_readl (sched_clock_reg) :0 ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return sched_clock_reg ?__raw_readl (sched_clock_reg) :0 ; }static int __init mxc_clocksource_init (struct clk *timer_clk)
@@ -129,7 +120,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk) sched_clock_reg = reg; -init_sched_clock (&cd, mxc_update_sched_clock,32 , c); +setup_sched_clock (mxc_read_sched_clock,32 , c);return clocksource_mmio_init (reg,"mxc_timer1" , c,200 ,32 , clocksource_mmio_readl_up); }
arch/arm/plat-nomadik/timer.c +3 -14
@@ -30,23 +30,12 @@ void __iomem *mtu_base; /* Assigned by machine code */* local implementation which uses the clocksource to get some * better resolution when scheduling the kernel. */ -static DEFINE_CLOCK_DATA (cd); - -unsigned long long notrace sched_clock (void ) +static u32 nomadik_read_sched_clock (void ) { -u32 cyc; -if (unlikely (!mtu_base))return 0 ; - cyc = -readl (mtu_base +MTU_VAL (0 )); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace nomadik_update_sched_clock(void) -{ -u32 cyc = -readl (mtu_base +MTU_VAL (0 )); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return -readl (mtu_base +MTU_VAL (0 )); }/* Clockevent device: use one-shot mode */
@@ -154,7 +143,7 @@ void __init nmdk_timer_init(void)pr_err ("timer: failed to initialize clock source %s\n" ,"mtu_0" ); -init_sched_clock (&cd, nomadik_update_sched_clock,32 , rate); +setup_sched_clock (nomadik_setup_sched_clock,32 , rate);/* Timer 1 is used for events */
arch/arm/plat-omap/counter_32k.c +3 -36
@@ -37,41 +37,9 @@ static void __iomem *timer_32k_base;#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 -/* -* Returns current time from boot in nsecs. It's OK for this to wrap -* around for now, as it's just a relative time stamp. -*/ -static DEFINE_CLOCK_DATA (cd); - -/* -* Constants generated by clocks_calc_mult_shift(m, s, 32768, NSEC_PER_SEC, 60). -* This gives a resolution of about 30us and a wrap period of about 36hrs. -*/ -#define SC_MULT 4000000000u -#define SC_SHIFT 17 - -static inline unsigned long long notrace _omap_32k_sched_clock (void ) -{ -u32 cyc = timer_32k_base ?__raw_readl (timer_32k_base) :0 ; -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 ,SC_MULT ,SC_SHIFT ); -} - -#if defined(CONFIG_OMAP_32K_TIMER ) && !defined(CONFIG_OMAP_MPU_TIMER ) -unsigned long long notrace sched_clock (void ) -{ -return _omap_32k_sched_clock (); -} -#else -unsigned long long notrace omap_32k_sched_clock (void ) -{ -return _omap_32k_sched_clock (); -} -#endif - -static void notrace omap_update_sched_clock(void) +u32 omap_32k_read_sched_clock (void ) { -u32 cyc = timer_32k_base ?__raw_readl (timer_32k_base) :0 ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return timer_32k_base ?__raw_readl (timer_32k_base) :0 ; }/**
@@ -147,8 +115,7 @@ int __init omap_init_clocksource_32k(void) clocksource_mmio_readl_up)) printk(err, "32k_counter"); -init_fixed_sched_clock (&cd, omap_update_sched_clock,32 , -32768 ,SC_MULT ,SC_SHIFT ); +setup_sched_clock (omap_32k_read_sched_clock,32 ,32768 ); }return 0 ; }
arch/arm/plat-omap/include/plat/common.h +1 -1
@@ -41,7 +41,7 @@ extern struct sys_timer omap3_secure_timer;extern struct sys_timer omap4_timer;extern bool omap_32k_timer_init (void );extern int __init omap_init_clocksource_32k (void ); -extern unsigned long long notrace omap_32k_sched_clock (void ); +extern u32 omap_32k_read_sched_clock (void );extern void omap_reserve (void );
arch/arm/plat-orion/time.c +3 -17
@@ -60,24 +60,10 @@ static u32 ticks_per_jiffy;* Orion's sched_clock implementation. It has a resolution of * at least 7.5ns (133MHz TCLK). */ -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 orion_read_sched_clock (void ) { -u32 cyc = ~readl (timer_base +TIMER0_VAL_OFF ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - - -static void notrace orion_update_sched_clock(void) -{ -u32 cyc = ~readl (timer_base +TIMER0_VAL_OFF ); -update_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void __init setup_sched_clock (unsigned long tclk) -{ -init_sched_clock (&cd, orion_update_sched_clock,32 , tclk); +return ~readl (timer_base +TIMER0_VAL_OFF ); }/*
@@ -217,7 +203,7 @@ orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask,/* * Set scale and timer for sched_clock. */ -setup_sched_clock (tclk); +setup_sched_clock (orion_read_sched_clock,32 , tclk);/* * Setup free-running clocksource timer (interrupts
arch/arm/plat-s5p/s5p-time.c +3 -15
@@ -321,26 +321,14 @@ static void __iomem *s5p_timer_reg(void)* this wraps around for now, since it is just a relative time * stamp. (Inspired by U300 implementation.) */ -static DEFINE_CLOCK_DATA (cd); - -unsigned long long notrace sched_clock (void ) -{ -void __iomem *reg =s5p_timer_reg (); - -if (!reg) -return 0 ; - -return cyc_to_sched_clock (&cd, ~__raw_readl (reg), (u32 )~0 ); -} - -static void notrace s5p_update_sched_clock(void) +static u32 s5p_read_sched_clock (void ) {void __iomem *reg =s5p_timer_reg ();if (!reg)return ; -update_sched_clock (&cd, ~__raw_readl (reg), (u32 )~0 ); +return ~__raw_readl (reg); }static void __init s5p_clocksource_init (void )
@@ -358,7 +346,7 @@ static void __init s5p_clocksource_init(void)s5p_time_setup (timer_source.source_id,TCNT_MAX );s5p_time_start (timer_source.source_id,PERIODIC ); -init_sched_clock (&cd, s5p_update_sched_clock,32 , clock_rate); +setup_sched_clock (s5p_read_sched_clock,32 , clock_rate);if (clocksource_mmio_init (s5p_timer_reg (),"s5p_clocksource_timer" , clock_rate,250 ,32 , clocksource_mmio_readl_down))
arch/arm/plat-versatile/sched-clock.c +5 -22
@@ -24,35 +24,18 @@#include <asm/sched_clock.h> #include <plat/sched_clock.h> -static DEFINE_CLOCK_DATA (cd);static void __iomem *ctr; -/* -* Constants generated by clocks_calc_mult_shift(m, s, 24MHz, NSEC_PER_SEC, 60). -* This gives a resolution of about 41ns and a wrap period of about 178s. -*/ -#define SC_MULT 2796202667u -#define SC_SHIFT 26 - -unsigned long long notrace sched_clock (void ) +static u32 versatile_read_sched_clock (void ) { -if (ctr) { -u32 cyc =readl (ctr); -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 , -SC_MULT ,SC_SHIFT ); - }else -return 0 ; -} +if (ctr) +return readl (ctr); -static void notrace versatile_update_sched_clock(void) -{ -u32 cyc =readl (ctr); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return 0 ; }void __init versatile_sched_clock_init (void __iomem *reg,unsigned long rate) { ctr = reg; -init_fixed_sched_clock (&cd, versatile_update_sched_clock, -32 , rate,SC_MULT ,SC_SHIFT ); +setup_sched_clock (versatile_read_sched_clock,32 , rate); }
Signature · 1 line
1.7.0.4
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 19 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).Tested on 11MPCore, OMAP4 and Tegra.
Quoted 16 lines
Cc Imre Kaloz <[email protected]>Cc Krzysztof Halasa <[email protected]>Cc Tony Lindgren <[email protected]>Cc Eric Miao <[email protected]>Cc Colin Cross <[email protected]>Cc Erik Gilling <[email protected]>Cc Olof Johansson <[email protected]>Cc Linus Walleij <[email protected]>Cc Sascha Hauer <[email protected]>Cc Alessandro Rubini <[email protected]>Cc STEricsson <[email protected]>Cc Lennert Buytenhek <[email protected]>Cc Nicolas Pitre <[email protected]>Cc Ben Dooks <[email protected]>Cc Kukjin Kim <[email protected]>Signed-off-by Marc Zyngier <[email protected]>
For Nomadik, U300.
Thanks!
Linus Walleij
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
In reply to Marc ZyngierQuoted 11 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.
Quoted 5 lines
This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).
There are similar patchsets that move sched_clock into clocksource code. That seems like a cleaner approach to me.
http://thread.gmane.org/gmane.linux.kernel/844872
http://www.spinics.net/lists/arm-kernel/msg122716.html
Rob
Quoted 974 lines
Tested on 11MPCore, OMAP4 and Tegra.
Cc Imre Kaloz <[email protected]>Cc Krzysztof Halasa <[email protected]>Cc Tony Lindgren <[email protected]>Cc Eric Miao <[email protected]>Cc Colin Cross <[email protected]>Cc Erik Gilling <[email protected]>Cc Olof Johansson <[email protected]>Cc Linus Walleij <[email protected]>Cc Sascha Hauer <[email protected]>Cc Alessandro Rubini <[email protected]>Cc STEricsson <[email protected]>Cc Lennert Buytenhek <[email protected]>Cc Nicolas Pitre <[email protected]>Cc Ben Dooks <[email protected]>Cc Kukjin Kim <[email protected]>Signed-off-by Marc Zyngier <[email protected]>---
Based on v3.0-rc1.arch/arm/include/asm/sched_clock.h | 108 +----------------------------- arch/arm/kernel/sched_clock.c | 97 +++++++++++++++++++++++++-- arch/arm/mach-ixp4xx/common.c | 15 +--- arch/arm/mach-mmp/time.c | 15 +--- arch/arm/mach-omap1/time.c | 57 +--------------- arch/arm/mach-omap2/timer.c | 20 +----- arch/arm/mach-pxa/time.c | 14 +--- arch/arm/mach-sa1100/time.c | 27 +------- arch/arm/mach-tegra/timer.c | 23 +------ arch/arm/mach-u300/timer.c | 14 +--- arch/arm/plat-iop/time.c | 15 +--- arch/arm/plat-mxc/time.c | 15 +--- arch/arm/plat-nomadik/timer.c | 17 +---- arch/arm/plat-omap/counter_32k.c | 39 +---------- arch/arm/plat-omap/include/plat/common.h | 2 +- arch/arm/plat-orion/time.c | 20 +----- arch/arm/plat-s5p/s5p-time.c | 18 +---- arch/arm/plat-versatile/sched-clock.c | 27 ++------ 18 files changed, 141 insertions(+), 402 deletions(-)arch/arm/include/asm/sched_clock.h +1
-107@@ -8,113 +8,7 @@#ifndef ASM_SCHED_CLOCK #define ASM_SCHED_CLOCK -#include <linux/kernel.h> -#include <linux/types.h> - -struct clock_data { -u64 epoch_ns; -u32 epoch_cyc; -u32 epoch_cyc_copy; -u32 mult; -u32 shift; -}; - -#define DEFINE_CLOCK_DATA (name) struct clock_data name - -static inline u64 cyc_to_ns (u64 cyc,u32 mult,u32 shift) -{ -return (cyc * mult) >> shift; -} - -/* -* Atomically update the sched_clock epoch. Your update callback will -* be called from a timer before the counter wraps - read the current -* counter value, and call this function to safely move the epochs -* forward. Only use this from the update callback. -*/ -static inline void update_sched_clock (struct clock_data *cd,u32 cyc,u32 mask) -{ -unsigned long flags; -u64 ns = cd->epoch_ns + -cyc_to_ns ((cyc - cd->epoch_cyc) & mask, cd->mult, cd->shift); - -/* -* Write epoch_cyc and epoch_ns in a way that the update is -* detectable in cyc_to_fixed_sched_clock(). -*/ -raw_local_irq_save (flags); - cd->epoch_cyc = cyc; -smp_wmb (); - cd->epoch_ns = ns; -smp_wmb (); - cd->epoch_cyc_copy = cyc; -raw_local_irq_restore (flags); -} - -/* -* If your clock rate is known at compile time, using this will allow -* you to optimize the mult/shift loads away. This is paired with -* init_fixed_sched_clock() to ensure that your mult/shift are correct. -*/ -static inline unsigned long long cyc_to_fixed_sched_clock (struct clock_data *cd, -u32 cyc,u32 mask,u32 mult,u32 shift) -{ -u64 epoch_ns; -u32 epoch_cyc; - -/* -* Load the epoch_cyc and epoch_ns atomically. We do this by -* ensuring that we always write epoch_cyc, epoch_ns and -* epoch_cyc_copy in strict order, and read them in strict order. -* If epoch_cyc and epoch_cyc_copy are not equal, then we're in -* the middle of an update, and we should repeat the load. -*/ -do { - epoch_cyc = cd->epoch_cyc; -smp_rmb (); - epoch_ns = cd->epoch_ns; -smp_rmb (); - }while (epoch_cyc != cd->epoch_cyc_copy); - -return epoch_ns +cyc_to_ns ((cyc - epoch_cyc) & mask, mult, shift); -} - -/* -* Otherwise, you need to use this, which will obtain the mult/shift -* from the clock_data structure. Use init_sched_clock() with this. -*/ -static inline unsigned long long cyc_to_sched_clock (struct clock_data *cd, -u32 cyc,u32 mask) -{ -return cyc_to_fixed_sched_clock (cd, cyc, mask, cd->mult, cd->shift); -} - -/* -* Initialize the clock data - calculate the appropriate multiplier -* and shift. Also setup a timer to ensure that the epoch is refreshed -* at the appropriate time interval, which will call your update -* handler. -*/ -void init_sched_clock (struct clock_data *,void (*)(void ), -unsigned int ,unsigned long ); - -/* -* Use this initialization function rather than init_sched_clock() if -* you're using cyc_to_fixed_sched_clock, which will warn if your -* constants are incorrect. -*/ -static inline void init_fixed_sched_clock (struct clock_data *cd, -void (*update)(void ),unsigned int bits,unsigned long rate, -u32 mult,u32 shift) -{ -init_sched_clock (cd, update, bits, rate); -if (cd->mult != mult || cd->shift != shift) { -pr_crit ("sched_clock: wrong multiply/shift: %u>>%u vs calculated %u>>%u\n" -"sched_clock: fix multiply/shift to avoid scheduler hiccups\n" , - mult, shift, cd->mult, cd->shift); - } -} -extern void sched_clock_postinit (void ); +extern void setup_sched_clock (u32 (*read)(void ),int bits,unsigned long rate);#endif arch/arm/kernel/sched_clock.c +90
-7@@ -14,25 +14,88 @@#include <asm/sched_clock.h> +struct clock_data { +u64 epoch_ns; +u32 epoch_cyc; +u32 epoch_cyc_copy; +u32 mult; +u32 shift; +}; +static void sched_clock_poll (unsigned long wrap_ticks); static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0); -static void (*sched_clock_update_fn)(void ); + +static struct clock_data cd; +static u32 sched_clock_mask; +static u32 __read_mostly (*read_sched_clock)(void ); + +static inline u64 cyc_to_ns (u64 cyc,u32 mult,u32 shift) +{ +return (cyc * mult) >> shift; +} + +static unsigned long long cyc_to_sched_clock (struct clock_data *cd, +u32 cyc,u32 mask) +{ +u64 epoch_ns; +u32 epoch_cyc; + +/* +* Load the epoch_cyc and epoch_ns atomically. We do this by +* ensuring that we always write epoch_cyc, epoch_ns and +* epoch_cyc_copy in strict order, and read them in strict order. +* If epoch_cyc and epoch_cyc_copy are not equal, then we're in +* the middle of an update, and we should repeat the load. +*/ +do { + epoch_cyc = cd->epoch_cyc; +smp_rmb (); + epoch_ns = cd->epoch_ns; +smp_rmb (); + }while (epoch_cyc != cd->epoch_cyc_copy); + +return epoch_ns +cyc_to_ns ((cyc - epoch_cyc) & mask, cd->mult, cd->shift); +} + +/* +* Atomically update the sched_clock epoch. +*/ +static void notrace update_sched_clock(void) +{ +unsigned long flags; +u32 cyc; +u64 ns; + + cyc =read_sched_clock (); + ns = cd.epoch_ns + +cyc_to_ns ((cyc - cd.epoch_cyc) & sched_clock_mask, + cd.mult, cd.shift); +/* +* Write epoch_cyc and epoch_ns in a way that the update is +* detectable in cyc_to_fixed_sched_clock(). +*/ +raw_local_irq_save (flags); + cd.epoch_cyc = cyc; +smp_wmb (); + cd.epoch_ns = ns; +smp_wmb (); + cd.epoch_cyc_copy = cyc; +raw_local_irq_restore (flags); +}static void sched_clock_poll (unsigned long wrap_ticks) {mod_timer (&sched_clock_timer,round_jiffies (jiffies + wrap_ticks)); -sched_clock_update_fn (); +update_sched_clock (); } -void __init init_sched_clock (struct clock_data *cd,void (*update)(void ), -unsigned int clock_bits,unsigned long rate) +static void __init init_sched_clock (struct clock_data *cd, +unsigned int clock_bits,unsigned long rate) {unsigned long r, w;u64 res, wrap;char r_unit; - sched_clock_update_fn = update; -/* calculate the mult/shift to convert counter ticks to ns. */ clocks_calc_mult_shift (&cd->mult, &cd->shift, rate,NSEC_PER_SEC ,0 );@@ -60,7 +123,7 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),* sets the initial epoch. */ sched_clock_timer.data =msecs_to_jiffies (w - (w /10 )); -update (); +update_sched_clock ();/* * Ensure that sched_clock() starts off at 0ns @@ -68,6 +131,26 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void), cd->epoch_ns =0 ; } +unsigned long long notrace sched_clock (void ) +{ +if (read_sched_clock) { +u32 cyc =read_sched_clock (); +return cyc_to_sched_clock (&cd, cyc, sched_clock_mask); + } + +return (unsigned long long )(jiffies -INITIAL_JIFFIES ) + * (NSEC_PER_SEC /HZ ); +} + +void __init setup_sched_clock (u32 (*read)(void ),int bits,unsigned long rate) +{ +BUG_ON (bits >32 ); + read_sched_clock = read; + sched_clock_mask = (1 << bits) -1 ; +init_sched_clock (&cd, bits, rate); +pr_debug ("Registered %pF as sched_clock source\n" , read); +} +void __init sched_clock_postinit (void ) {sched_clock_poll (sched_clock_timer.data);arch/arm/mach-ixp4xx/common.c +3
-12@@ -402,18 +402,9 @@ void __init ixp4xx_sys_init(void)/* * sched_clock() */ -static DEFINE_CLOCK_DATA (cd); - -unsigned long long notrace sched_clock (void ) +static u32 ixp4xx_read_sched_clock (void ) { -u32 cyc = *IXP4XX_OSTS ; -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace ixp4xx_update_sched_clock(void) -{ -u32 cyc = *IXP4XX_OSTS ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return *IXP4XX_OSTS ; }/* @@ -429,7 +420,7 @@ unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;EXPORT_SYMBOL (ixp4xx_timer_freq);static void __init ixp4xx_clocksource_init (void ) { -init_sched_clock (&cd, ixp4xx_update_sched_clock,32 , ixp4xx_timer_freq); +setup_sched_clock (ixp4xx_read_sched_clock,32 , ixp4xx_timer_freq);clocksource_mmio_init (NULL ,"OSTS" , ixp4xx_timer_freq,200 ,32 , ixp4xx_clocksource_read);arch/arm/mach-mmp/time.c +3
-12@@ -42,8 +42,6 @@#define MAX_DELTA (0xfffffffe)#define MIN_DELTA (16) -static DEFINE_CLOCK_DATA (cd); -/* * FIXME: the timer needs some delay to stablize the counter capture */ @@ -59,16 +57,9 @@ static inline uint32_t timer_read(void)return __raw_readl (TIMERS_VIRT_BASE +TMR_CVWR (0 )); } -unsigned long long notrace sched_clock (void ) +static u32 mmp_read_sched_clock (void ) { -u32 cyc =timer_read (); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace mmp_update_sched_clock(void) -{ -u32 cyc =timer_read (); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return timer_read (); }static irqreturn_t timer_interrupt (int irq,void *dev_id)@@ -175,7 +166,7 @@ void __init timer_init(int irq) {timer_config (); -init_sched_clock (&cd, mmp_update_sched_clock,32 ,CLOCK_TICK_RATE ); +setup_sched_clock (mmp_read_sched_clock,32 ,CLOCK_TICK_RATE ); ckevt.mult =div_sc (CLOCK_TICK_RATE ,NSEC_PER_SEC , ckevt.shift); ckevt.max_delta_ns =clockevent_delta2ns (MAX_DELTA , &ckevt);arch/arm/mach-omap1/time.c +4
-53@@ -190,30 +190,9 @@ static __init void omap_init_mpu_timer(unsigned long rate)* --------------------------------------------------------------------------- */ -static DEFINE_CLOCK_DATA (cd); - -static inline unsigned long long notrace _omap_mpu_sched_clock (void ) -{ -u32 cyc = ~omap_mpu_timer_read (1 ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -#ifndef CONFIG_OMAP_32K_TIMER -unsigned long long notrace sched_clock (void ) -{ -return _omap_mpu_sched_clock (); -} -#else -static unsigned long long notrace omap_mpu_sched_clock (void ) -{ -return _omap_mpu_sched_clock (); -} -#endif - -static void notrace mpu_update_sched_clock(void) +static u32 omap_mpu_read_sched_clock (void ) { -u32 cyc = ~omap_mpu_timer_read (1 ); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return ~omap_mpu_timer_read (1 ); }static void __init omap_init_clocksource (unsigned long rate)@@ -223,7 +202,7 @@ static void __init omap_init_clocksource(unsigned long rate)"%s: can't register clocksource!\n" ;omap_mpu_timer_start (1 , ~0 ,1 ); -init_sched_clock (&cd, mpu_update_sched_clock,32 , rate); +setup_sched_clock (omap_mpu_read_sched_clock,32 , rate);if (clocksource_mmio_init (&timer->read_tim,"mpu_timer2" , rate,300 ,32 , clocksource_mmio_readl_down))@@ -254,30 +233,6 @@ static inline void omap_mpu_timer_init(void) }#endif /* CONFIG_OMAP_MPU_TIMER */ -#if defined(CONFIG_OMAP_MPU_TIMER ) && defined(CONFIG_OMAP_32K_TIMER ) -static unsigned long long (*preferred_sched_clock)(void ); - -unsigned long long notrace sched_clock (void ) -{ -if (!preferred_sched_clock) -return 0 ; - -return preferred_sched_clock (); -} - -static inline void preferred_sched_clock_init (bool use_32k_sched_clock) -{ -if (use_32k_sched_clock) - preferred_sched_clock = omap_32k_sched_clock; -else - preferred_sched_clock = omap_mpu_sched_clock; -} -#else -static inline void preferred_sched_clock_init (bool use_32k_sched_clcok) -{ -} -#endif -static inline int omap_32k_timer_usable (void ) {int res = false;@@ -299,12 +254,8 @@ static inline int omap_32k_timer_usable(void)*/ static void __init omap1_timer_init (void ) { -if (omap_32k_timer_usable ()) { -preferred_sched_clock_init (1 ); - }else { +if (!omap_32k_timer_usable ())omap_mpu_timer_init (); -preferred_sched_clock_init (0 ); - } }struct sys_timer omap1_timer = {arch/arm/mach-omap2/timer.c +4
-16@@ -248,7 +248,6 @@ static struct omap_dm_timer clksrc;/* * clocksource */ -static DEFINE_CLOCK_DATA (cd);static cycle_t clocksource_read_cycles (struct clocksource *cs) {return (cycle_t )__omap_dm_timer_read_counter (clksrc.io_base,1 );@@ -262,23 +261,12 @@ static struct clocksource clocksource_gpt = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void notrace dmtimer_update_sched_clock(void) +static u32 dmtimer_read_sched_clock (void ) { -u32 cyc; - - cyc =__omap_dm_timer_read_counter (clksrc.io_base,1 ); - -update_sched_clock (&cd, cyc, (u32 )~0 ); -} - -unsigned long long notrace sched_clock (void ) -{ -u32 cyc =0 ; -if (clksrc.reserved) - cyc =__omap_dm_timer_read_counter (clksrc.io_base,1 ); +return __omap_dm_timer_read_counter (clksrc.io_base,1 ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); +return 0 ; }/* Setup free-running counter for clocksource */ @@ -294,7 +282,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, gptimer_id, clksrc.rate);__omap_dm_timer_load_start (clksrc.io_base,OMAP_TIMER_CTRL_ST ,0 ,1 ); -init_sched_clock (&cd, dmtimer_update_sched_clock,32 , clksrc.rate); +setup_sched_clock (dmtimer_read_sched_clock,32 , clksrc.rate);if (clocksource_register_hz (&clocksource_gpt, clksrc.rate)) pr_err("Could not register clocksource %s\n",arch/arm/mach-pxa/time.c +3
-11@@ -32,18 +32,10 @@* long as there is always less than 582 seconds between successive * calls to sched_clock() which should always be the case in practice. */ -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 pxa_read_sched_clock (void ) { -u32 cyc =OSCR ; -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace pxa_update_sched_clock(void) -{ -u32 cyc =OSCR ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return OSCR ; }@@ -119,7 +111,7 @@ static void __init pxa_timer_init(void)OIER =0 ;OSSR =OSSR_M0 |OSSR_M1 |OSSR_M2 |OSSR_M3 ; -init_sched_clock (&cd, pxa_update_sched_clock,32 , clock_tick_rate); +setup_sched_clock (pxa_read_sched_clock,32 , clock_tick_rate);clockevents_calc_mult_shift (&ckevt_pxa_osmr0, clock_tick_rate,4 ); ckevt_pxa_osmr0.max_delta_ns =arch/arm/mach-sa1100/time.c +3
-24@@ -20,29 +20,9 @@#include <asm/sched_clock.h> #include <mach/hardware.h> -/* -* This is the SA11x0 sched_clock implementation. -*/ -static DEFINE_CLOCK_DATA (cd); - -/* -* Constants generated by clocks_calc_mult_shift(m, s, 3.6864MHz, -* NSEC_PER_SEC, 60). -* This gives a resolution of about 271ns and a wrap period of about 19min. -*/ -#define SC_MULT 2275555556u -#define SC_SHIFT 23 - -unsigned long long notrace sched_clock (void ) -{ -u32 cyc =OSCR ; -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 ,SC_MULT ,SC_SHIFT ); -} - -static void notrace sa1100_update_sched_clock(void) +static u32 sa100_read_sched_clock (void ) { -u32 cyc =OSCR ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return OSCR ; }#define MIN_OSCR_DELTA 2@@ -109,8 +89,7 @@ static void __init sa1100_timer_init(void)OIER =0 ;OSSR =OSSR_M0 |OSSR_M1 |OSSR_M2 |OSSR_M3 ; -init_fixed_sched_clock (&cd, sa1100_update_sched_clock,32 , -3686400 ,SC_MULT ,SC_SHIFT ); +setup_sched_clock (sa1100_read_sched_clock,32 ,3686400 );clockevents_calc_mult_shift (&ckevt_sa1100_osmr0,3686400 ,4 ); ckevt_sa1100_osmr0.max_delta_ns =arch/arm/mach-tegra/timer.c +3
-20@@ -106,25 +106,9 @@ static struct clock_event_device tegra_clockevent = { .set_mode = tegra_timer_set_mode, }; -static DEFINE_CLOCK_DATA (cd); - -/* -* Constants generated by clocks_calc_mult_shift(m, s, 1MHz, NSEC_PER_SEC, 60). -* This gives a resolution of about 1us and a wrap period of about 1h11min. -*/ -#define SC_MULT 4194304000u -#define SC_SHIFT 22 - -unsigned long long notrace sched_clock (void ) -{ -u32 cyc =timer_readl (TIMERUS_CNTR_1US ); -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 ,SC_MULT ,SC_SHIFT ); -} - -static void notrace tegra_update_sched_clock(void) +static u32 tegra_read_sched_clock (void ) { -u32 cyc =timer_readl (TIMERUS_CNTR_1US ); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return timer_readl (TIMERUS_CNTR_1US ); }/* @@ -218,8 +202,7 @@ static void __init tegra_init_timer(void)WARN (1 ,"Unknown clock rate" ); } -init_fixed_sched_clock (&cd, tegra_update_sched_clock,32 , -1000000 ,SC_MULT ,SC_SHIFT ); +setup_sched_clock (tegra_read_sched_clock,32 ,1000000 );if (clocksource_mmio_init (timer_reg_base +TIMERUS_CNTR_1US ,"timer_us" ,1000000 ,300 ,32 , clocksource_mmio_readl_up)) {arch/arm/mach-u300/timer.c +3
-11@@ -337,18 +337,10 @@ static struct irqaction u300_timer_irq = {* this wraps around for now, since it is just a relative time * stamp. (Inspired by OMAP implementation.) */ -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 u300_read_sched_clock (void ) { -u32 cyc =readl (U300_TIMER_APP_VBASE +U300_TIMER_APP_GPT2CC ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace u300_update_sched_clock(void) -{ -u32 cyc =readl (U300_TIMER_APP_VBASE +U300_TIMER_APP_GPT2CC ); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return readl (U300_TIMER_APP_VBASE +U300_TIMER_APP_GPT2CC ); }@@ -366,7 +358,7 @@ static void __init u300_timer_init(void)clk_enable (clk); rate =clk_get_rate (clk); -init_sched_clock (&cd, u300_update_sched_clock,32 , rate); +setup_sched_clock (u300_read_sched_clock,32 , rate);/* * Disable the "OS" and "DD" timers - these are designed for Symbian! arch/arm/plat-iop/time.c +3
-12@@ -51,21 +51,12 @@ static struct clocksource iop_clocksource = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static DEFINE_CLOCK_DATA (cd); -/* * IOP sched_clock() implementation via its clocksource. */ -unsigned long long notrace sched_clock (void ) +static u32 iop_read_sched_clock (void ) { -u32 cyc =0xffffffffu -read_tcr1 (); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace iop_update_sched_clock(void) -{ -u32 cyc =0xffffffffu -read_tcr1 (); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return 0xffffffffu -read_tcr1 (); }/* @@ -151,7 +142,7 @@ void __init iop_init_time(unsigned long tick_rate) {u32 timer_ctl; -init_sched_clock (&cd, iop_update_sched_clock,32 , tick_rate); +setup_sched_clock (iop_read_sched_clock,32 , tick_rate); ticks_per_jiffy =DIV_ROUND_CLOSEST (tick_rate,HZ ); iop_tick_rate = tick_rate;arch/arm/plat-mxc/time.c +3
-12@@ -108,18 +108,9 @@ static void gpt_irq_acknowledge(void)static void __iomem *sched_clock_reg; -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 mxc_read_sched_clock (void ) { -cycle_t cyc = sched_clock_reg ?__raw_readl (sched_clock_reg) :0 ; - -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace mxc_update_sched_clock(void) -{ -cycle_t cyc = sched_clock_reg ?__raw_readl (sched_clock_reg) :0 ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return sched_clock_reg ?__raw_readl (sched_clock_reg) :0 ; }static int __init mxc_clocksource_init (struct clk *timer_clk)@@ -129,7 +120,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk) sched_clock_reg = reg; -init_sched_clock (&cd, mxc_update_sched_clock,32 , c); +setup_sched_clock (mxc_read_sched_clock,32 , c);return clocksource_mmio_init (reg,"mxc_timer1" , c,200 ,32 , clocksource_mmio_readl_up); }arch/arm/plat-nomadik/timer.c +3
-14@@ -30,23 +30,12 @@ void __iomem *mtu_base; /* Assigned by machine code */* local implementation which uses the clocksource to get some * better resolution when scheduling the kernel. */ -static DEFINE_CLOCK_DATA (cd); - -unsigned long long notrace sched_clock (void ) +static u32 nomadik_read_sched_clock (void ) { -u32 cyc; -if (unlikely (!mtu_base))return 0 ; - cyc = -readl (mtu_base +MTU_VAL (0 )); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void notrace nomadik_update_sched_clock(void) -{ -u32 cyc = -readl (mtu_base +MTU_VAL (0 )); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return -readl (mtu_base +MTU_VAL (0 )); }/* Clockevent device: use one-shot mode */ @@ -154,7 +143,7 @@ void __init nmdk_timer_init(void)pr_err ("timer: failed to initialize clock source %s\n" ,"mtu_0" ); -init_sched_clock (&cd, nomadik_update_sched_clock,32 , rate); +setup_sched_clock (nomadik_setup_sched_clock,32 , rate);/* Timer 1 is used for events */ arch/arm/plat-omap/counter_32k.c +3
-36@@ -37,41 +37,9 @@ static void __iomem *timer_32k_base;#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 -/* -* Returns current time from boot in nsecs. It's OK for this to wrap -* around for now, as it's just a relative time stamp. -*/ -static DEFINE_CLOCK_DATA (cd); - -/* -* Constants generated by clocks_calc_mult_shift(m, s, 32768, NSEC_PER_SEC, 60). -* This gives a resolution of about 30us and a wrap period of about 36hrs. -*/ -#define SC_MULT 4000000000u -#define SC_SHIFT 17 - -static inline unsigned long long notrace _omap_32k_sched_clock (void ) -{ -u32 cyc = timer_32k_base ?__raw_readl (timer_32k_base) :0 ; -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 ,SC_MULT ,SC_SHIFT ); -} - -#if defined(CONFIG_OMAP_32K_TIMER ) && !defined(CONFIG_OMAP_MPU_TIMER ) -unsigned long long notrace sched_clock (void ) -{ -return _omap_32k_sched_clock (); -} -#else -unsigned long long notrace omap_32k_sched_clock (void ) -{ -return _omap_32k_sched_clock (); -} -#endif - -static void notrace omap_update_sched_clock(void) +u32 omap_32k_read_sched_clock (void ) { -u32 cyc = timer_32k_base ?__raw_readl (timer_32k_base) :0 ; -update_sched_clock (&cd, cyc, (u32 )~0 ); +return timer_32k_base ?__raw_readl (timer_32k_base) :0 ; }/** @@ -147,8 +115,7 @@ int __init omap_init_clocksource_32k(void) clocksource_mmio_readl_up)) printk(err, "32k_counter"); -init_fixed_sched_clock (&cd, omap_update_sched_clock,32 , -32768 ,SC_MULT ,SC_SHIFT ); +setup_sched_clock (omap_32k_read_sched_clock,32 ,32768 ); }return 0 ; }arch/arm/plat-omap/include/plat/common.h +1
-1@@ -41,7 +41,7 @@ extern struct sys_timer omap3_secure_timer;extern struct sys_timer omap4_timer;extern bool omap_32k_timer_init (void );extern int __init omap_init_clocksource_32k (void ); -extern unsigned long long notrace omap_32k_sched_clock (void ); +extern u32 omap_32k_read_sched_clock (void );extern void omap_reserve (void );arch/arm/plat-orion/time.c +3
-17@@ -60,24 +60,10 @@ static u32 ticks_per_jiffy;* Orion's sched_clock implementation. It has a resolution of * at least 7.5ns (133MHz TCLK). */ -static DEFINE_CLOCK_DATA (cd); -unsigned long long notrace sched_clock (void ) +static u32 orion_read_sched_clock (void ) { -u32 cyc = ~readl (timer_base +TIMER0_VAL_OFF ); -return cyc_to_sched_clock (&cd, cyc, (u32 )~0 ); -} - - -static void notrace orion_update_sched_clock(void) -{ -u32 cyc = ~readl (timer_base +TIMER0_VAL_OFF ); -update_sched_clock (&cd, cyc, (u32 )~0 ); -} - -static void __init setup_sched_clock (unsigned long tclk) -{ -init_sched_clock (&cd, orion_update_sched_clock,32 , tclk); +return ~readl (timer_base +TIMER0_VAL_OFF ); }/* @@ -217,7 +203,7 @@ orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask,/* * Set scale and timer for sched_clock. */ -setup_sched_clock (tclk); +setup_sched_clock (orion_read_sched_clock,32 , tclk);/* * Setup free-running clocksource timer (interrupts arch/arm/plat-s5p/s5p-time.c +3
-15@@ -321,26 +321,14 @@ static void __iomem *s5p_timer_reg(void)* this wraps around for now, since it is just a relative time * stamp. (Inspired by U300 implementation.) */ -static DEFINE_CLOCK_DATA (cd); - -unsigned long long notrace sched_clock (void ) -{ -void __iomem *reg =s5p_timer_reg (); - -if (!reg) -return 0 ; - -return cyc_to_sched_clock (&cd, ~__raw_readl (reg), (u32 )~0 ); -} - -static void notrace s5p_update_sched_clock(void) +static u32 s5p_read_sched_clock (void ) {void __iomem *reg =s5p_timer_reg ();if (!reg)return ; -update_sched_clock (&cd, ~__raw_readl (reg), (u32 )~0 ); +return ~__raw_readl (reg); }static void __init s5p_clocksource_init (void )@@ -358,7 +346,7 @@ static void __init s5p_clocksource_init(void)s5p_time_setup (timer_source.source_id,TCNT_MAX );s5p_time_start (timer_source.source_id,PERIODIC ); -init_sched_clock (&cd, s5p_update_sched_clock,32 , clock_rate); +setup_sched_clock (s5p_read_sched_clock,32 , clock_rate);if (clocksource_mmio_init (s5p_timer_reg (),"s5p_clocksource_timer" , clock_rate,250 ,32 , clocksource_mmio_readl_down))arch/arm/plat-versatile/sched-clock.c +5
-22@@ -24,35 +24,18 @@#include <asm/sched_clock.h> #include <plat/sched_clock.h> -static DEFINE_CLOCK_DATA (cd);static void __iomem *ctr; -/* -* Constants generated by clocks_calc_mult_shift(m, s, 24MHz, NSEC_PER_SEC, 60). -* This gives a resolution of about 41ns and a wrap period of about 178s. -*/ -#define SC_MULT 2796202667u -#define SC_SHIFT 26 - -unsigned long long notrace sched_clock (void ) +static u32 versatile_read_sched_clock (void ) { -if (ctr) { -u32 cyc =readl (ctr); -return cyc_to_fixed_sched_clock (&cd, cyc, (u32 )~0 , -SC_MULT ,SC_SHIFT ); - }else -return 0 ; -} +if (ctr) +return readl (ctr); -static void notrace versatile_update_sched_clock(void) -{ -u32 cyc =readl (ctr); -update_sched_clock (&cd, cyc, (u32 )~0 ); +return 0 ; }void __init versatile_sched_clock_init (void __iomem *reg,unsigned long rate) { ctr = reg; -init_fixed_sched_clock (&cd, versatile_update_sched_clock, -32 , rate,SC_MULT ,SC_SHIFT ); +setup_sched_clock (versatile_read_sched_clock,32 , rate); }
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 18 lines · Rob Herring
Quoted 11 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.Quoted 5 lines
This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).
Quoted 6 lines
There are similar patchsets that move
sched_clockinto clocksource code. That seems like a cleaner approach to me.
+1, yeah would be better for clocksource to handle that if possible.
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 19 lines · Eric Miao
Quoted 18 lines · Rob Herring
Quoted 16 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).
Quoted 8 lines
Quoted 6 lines
There are similar patchsets that move
sched_clockinto clocksource code. That seems like a cleaner approach to me.+1, yeah would be better for clocksource to handle that if possible.
clocksources initialize too late, and we have platforms where the clocksource is not used for sched_clock.
If clocksources were suitable universally for sched_clock, sched_clock would not exist.
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
In reply to Eric MiaoQuoted 19 lines · Eric Miao
Quoted 18 lines · Rob Herring
Quoted 16 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).
Quoted 8 lines
Quoted 6 lines
There are similar patchsets that move
sched_clockinto clocksource code. That seems like a cleaner approach to me.+1, yeah would be better for clocksource to handle that if possible.
I'd be all for that, and I've waited a long time (April?) before posting that patch, hoping that a consensus would emerge on the clocksourse patches.
So far, nothing.
We need a solution to this problem. I really don't care which patch gets merged, so if someone thinks they can get the clocksource patches further, then by all mean, please do it.
Cheers,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 9 lines · Marc Zyngier
I'd be all for that, and I've waited a long time (April?) before posting that patch, hoping that a consensus would emerge on the clocksourse patches.
So far, nothing.
We need a solution to this problem. I really don't care which patch gets merged, so if someone thinks they can get the clocksource patches further, then by all mean, please do it.
I'll say it again, because you seem to have missed it. I don't think intimately tying sched_clock and clocksource stuff together is a good idea, especially as there's platforms where sched_clock is higher resolution than the clocksource. Plus, if it really is the case that any clocksource can be used for sched_clock, then we wouldn't have sched_clock at all.
So no, I don't think tying the two together is a good idea. Especially when it means that some platforms will end up with a lower resolution and/or slower implementation.
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 18 lines · Russell King - ARM Linux
Quoted 9 lines · Marc Zyngier
I'd be all for that, and I've waited a long time (April?) before posting that patch, hoping that a consensus would emerge on the clocksourse patches.
So far, nothing.
We need a solution to this problem. I really don't care which patch gets merged, so if someone thinks they can get the clocksource patches further, then by all mean, please do it.
I'll say it again, because you seem to have missed it. I don't think intimately tying
sched_clockand clocksource stuff together is a good idea, especially as there's platforms wheresched_clockis higher resolution than the clocksource. Plus, if it really is the case that any clocksource can be used forsched_clock, then we wouldn't havesched_clockat all.
Quoted 3 lines
So no, I don't think tying the two together is a good idea. Especially when it means that some platforms will end up with a lower resolution and/or slower implementation.
Fair enough. I'll carry on with my current patch then.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
In reply to Rob HerringQuoted 8 lines · Rob Herring
There are similar patchsets that move
sched_clockinto clocksource code. That seems like a cleaner approach to me.
It's been tried like three times before, and never survived testing in -next. Marc's patchset is less invasive and it makes things better, not worse. So let's take this stepwise, beginning with Marc's stuff.
Yours,
Linus Walleij
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
In reply to Marc ZyngierHi Marc,
Quoted 11 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.
Quoted 7 lines
This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).Tested on 11MPCore, OMAP4 and Tegra.
Tested on my 1176 platform and works nicely. However, shouldn't the read functions still be marked notrace so they don't appear in ftrace output?
On my (out of tree) platform, omitting notrace and having all of the ftrace bootup tests results in a hard lockup. Annotating the read function resolves this.
Jamie
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 22 lines · Jamie Iles
Hi Marc,
Quoted 11 lines · Marc Zyngier
sched_clock()is yet another blocker on the road to the single image. This patch implements an idea by Russell King:http://www.spinics.net/lists/linux-omap/msg49561.html
Instead of asking the platform to implement both
sched_clock()itself and the rollover callback, simply register aread()function, and let the ARM code care aboutsched_clock()itself, the conversion to ns and the rollover.sched_clock()uses thisread()function as an indirection to the platform code.Quoted 7 lines
This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the
*_fixed_sched_clockoptimization which could negatively impact some platforms (sa1100, tegra, versatile and omap).Tested on 11MPCore, OMAP4 and Tegra.
Quoted 7 lines
Tested on my 1176 platform and works nicely. However, shouldn't the read functions still be marked notrace so they don't appear in ftrace output?
On my (out of tree) platform, omitting notrace and having all of the ftrace bootup tests results in a hard lockup. Annotating the read function resolves this.
I'll update the patch to reflect this.
Many thanks for testing.
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
In reply to Jamie IlesQuoted 7 lines · Jamie Iles
Tested on my 1176 platform and works nicely. However, shouldn't the read functions still be marked notrace so they don't appear in ftrace output?
On my (out of tree) platform, omitting notrace and having all of the ftrace bootup tests results in a hard lockup. Annotating the read function resolves this.
Why not also convert ftrace to use clocksources ?
RFC PATCH 1/1 ARM: sched_clock: allow sched_clock to be selected at runtime
Quoted 10 lines · Russell King - ARM Linux
Quoted 7 lines · Jamie Iles
Tested on my 1176 platform and works nicely. However, shouldn't the read functions still be marked notrace so they don't appear in ftrace output?
On my (out of tree) platform, omitting notrace and having all of the ftrace bootup tests results in a hard lockup. Annotating the read function resolves this.
Why not also convert ftrace to use clocksources ?
I can't say I know enough about ftrace to say what the implications of that would be (other than a dependency on all platforms having a suitable clocksource).
Jamie