Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: Timers/counters/delay management

ARC700 includes 2 in-core 32bit timers TIMER0 and TIMER1.
Both have exactly same capabilies.

* programmable to count from TIMER<n>_CNT to TIMER<n>_LIMIT
* for count 0 and LIMIT ~1, provides a free-running counter by
auto-wrapping when limit is reached.
* optionally interrupt when LIMIT is reached (oneshot event semantics)
* rearming the interrupt provides periodic semantics
* run at CPU clk

ARC Linux uses TIMER0 for clockevent (periodic/oneshot) and TIMER1 for
clocksource (free-running clock).

Newer cores provide RTSC insn which gives a 64bit cpu clk snapshot hence
is more apt for clocksource when available.

SMP poses a bit of challenge for global timekeeping clocksource /
sched_clock() backend:
-TIMER1 based local clocks are out-of-sync hence can't be used
(thus we default to jiffies based cs as well as sched_clock() one/both
of which platform can override with it's specific hardware assist)
-RTSC is only allowed in SMP if it's cross-core-sync (Kconfig glue
ensures that) and thus usable for both requirements.

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Thomas Gleixner <tglx@linutronix.de>

+425
+11
arch/arc/include/asm/arcregs.h
··· 47 47 #define AUX_ITRIGGER 0x40d 48 48 #define AUX_IPULSE 0x415 49 49 50 + /* Timer related Aux registers */ 51 + #define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */ 52 + #define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */ 53 + #define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */ 54 + #define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */ 55 + #define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */ 56 + #define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */ 57 + 58 + #define TIMER_CTRL_IE (1 << 0) /* Interupt when Count reachs limit */ 59 + #define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */ 60 + 50 61 /* 51 62 * Floating Pt Registers 52 63 * Status regs are read-only (build-time) so need not be saved/restored
+20
arch/arc/include/asm/clk.h
··· 1 + /* 2 + * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _ASM_ARC_CLK_H 10 + #define _ASM_ARC_CLK_H 11 + 12 + /* Although we can't really hide core_freq, the accessor is still better way */ 13 + extern unsigned long core_freq; 14 + 15 + static inline unsigned long arc_get_core_freq(void) 16 + { 17 + return core_freq; 18 + } 19 + 20 + #endif
+68
arch/arc/include/asm/delay.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Delay routines using pre computed loops_per_jiffy value. 9 + * 10 + * vineetg: Feb 2012 11 + * -Rewrote in "C" to avoid dealing with availability of H/w MPY 12 + * -Also reduced the num of MPY operations from 3 to 2 13 + * 14 + * Amit Bhor: Codito Technologies 2004 15 + */ 16 + 17 + #ifndef __ASM_ARC_UDELAY_H 18 + #define __ASM_ARC_UDELAY_H 19 + 20 + #include <asm/param.h> /* HZ */ 21 + 22 + static inline void __delay(unsigned long loops) 23 + { 24 + __asm__ __volatile__( 25 + "1: sub.f %0, %0, 1 \n" 26 + " jpnz 1b \n" 27 + : "+r"(loops) 28 + : 29 + : "cc"); 30 + } 31 + 32 + extern void __bad_udelay(void); 33 + 34 + /* 35 + * Normal Math for computing loops in "N" usecs 36 + * -we have precomputed @loops_per_jiffy 37 + * -1 sec has HZ jiffies 38 + * loops per "N" usecs = ((loops_per_jiffy * HZ / 1000000) * N) 39 + * 40 + * Approximate Division by multiplication: 41 + * -Mathematically if we multiply and divide a number by same value the 42 + * result remains unchanged: In this case, we use 2^32 43 + * -> (loops_per_N_usec * 2^32 ) / 2^32 44 + * -> (((loops_per_jiffy * HZ / 1000000) * N) * 2^32) / 2^32 45 + * -> (loops_per_jiffy * HZ * N * 4295) / 2^32 46 + * 47 + * -Divide by 2^32 is very simply right shift by 32 48 + * -We simply need to ensure that the multiply per above eqn happens in 49 + * 64-bit precision (if CPU doesn't support it - gcc can emaulate it) 50 + */ 51 + 52 + static inline void __udelay(unsigned long usecs) 53 + { 54 + unsigned long loops; 55 + 56 + /* (long long) cast ensures 64 bit MPY - real or emulated 57 + * HZ * 4295 is pre-evaluated by gcc - hence only 2 mpy ops 58 + */ 59 + loops = ((long long)(usecs * 4295 * HZ) * 60 + (long long)(loops_per_jiffy)) >> 32; 61 + 62 + __delay(loops); 63 + } 64 + 65 + #define udelay(n) (__builtin_constant_p(n) ? ((n) > 20000 ? __bad_udelay() \ 66 + : __udelay(n)) : __udelay(n)) 67 + 68 + #endif /* __ASM_ARC_UDELAY_H */
+2
arch/arc/include/asm/irq.h
··· 19 19 extern void __init plat_init_IRQ(void); 20 20 extern int __init get_hw_config_num_irq(void); 21 21 22 + void __cpuinit arc_local_timer_setup(unsigned int cpu); 23 + 22 24 #endif
+18
arch/arc/include/asm/timex.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _ASM_ARC_TIMEX_H 10 + #define _ASM_ARC_TIMEX_H 11 + 12 + #define CLOCK_TICK_RATE 80000000 /* slated to be removed */ 13 + 14 + #include <asm-generic/timex.h> 15 + 16 + /* XXX: get_cycles() to be implemented with RTSC insn */ 17 + 18 + #endif /* _ASM_ARC_TIMEX_H */
+11
arch/arc/kernel/clk.c
··· 1 + /* 2 + * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #include <asm/clk.h> 10 + 11 + unsigned long core_freq = CONFIG_ARC_PLAT_CLK;
+295
arch/arc/kernel/time.c
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * vineetg: Jan 1011 9 + * -sched_clock( ) no longer jiffies based. Uses the same clocksource 10 + * as gtod 11 + * 12 + * Rajeshwarr/Vineetg: Mar 2008 13 + * -Implemented CONFIG_GENERIC_TIME (rather deleted arch specific code) 14 + * for arch independent gettimeofday() 15 + * -Implemented CONFIG_GENERIC_CLOCKEVENTS as base for hrtimers 16 + * 17 + * Vineetg: Mar 2008: Forked off from time.c which now is time-jiff.c 18 + */ 19 + 20 + /* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1 21 + * Each can programmed to go from @count to @limit and optionally 22 + * interrupt when that happens. 23 + * A write to Control Register clears the Interrupt 24 + * 25 + * We've designated TIMER0 for events (clockevents) 26 + * while TIMER1 for free running (clocksource) 27 + * 28 + * Newer ARC700 cores have 64bit clk fetching RTSC insn, preferred over TIMER1 29 + */ 30 + 31 + #include <linux/spinlock.h> 32 + #include <linux/interrupt.h> 33 + #include <linux/module.h> 34 + #include <linux/sched.h> 35 + #include <linux/kernel.h> 36 + #include <linux/interrupt.h> 37 + #include <linux/time.h> 38 + #include <linux/init.h> 39 + #include <linux/timex.h> 40 + #include <linux/profile.h> 41 + #include <linux/clocksource.h> 42 + #include <linux/clockchips.h> 43 + #include <asm/irq.h> 44 + #include <asm/arcregs.h> 45 + #include <asm/clk.h> 46 + 47 + #define ARC_TIMER_MAX 0xFFFFFFFF 48 + 49 + /********** Clock Source Device *********/ 50 + 51 + #ifdef CONFIG_ARC_HAS_RTSC 52 + 53 + int __cpuinit arc_counter_setup(void) 54 + { 55 + /* RTSC insn taps into cpu clk, needs no setup */ 56 + 57 + /* For SMP, only allowed if cross-core-sync, hence usable as cs */ 58 + return 1; 59 + } 60 + 61 + static cycle_t arc_counter_read(struct clocksource *cs) 62 + { 63 + unsigned long flags; 64 + union { 65 + #ifdef CONFIG_CPU_BIG_ENDIAN 66 + struct { u32 high, low; }; 67 + #else 68 + struct { u32 low, high; }; 69 + #endif 70 + cycle_t full; 71 + } stamp; 72 + 73 + flags = arch_local_irq_save(); 74 + 75 + __asm__ __volatile( 76 + " .extCoreRegister tsch, 58, r, cannot_shortcut \n" 77 + " rtsc %0, 0 \n" 78 + " mov %1, tsch \n" /* TSCH is extn core reg 58 */ 79 + : "=r" (stamp.low), "=r" (stamp.high)); 80 + 81 + arch_local_irq_restore(flags); 82 + 83 + return stamp.full; 84 + } 85 + 86 + static struct clocksource arc_counter = { 87 + .name = "ARC RTSC", 88 + .rating = 300, 89 + .read = arc_counter_read, 90 + .mask = CLOCKSOURCE_MASK(64), 91 + .flags = CLOCK_SOURCE_IS_CONTINUOUS, 92 + }; 93 + 94 + #else /* !CONFIG_ARC_HAS_RTSC */ 95 + 96 + static bool is_usable_as_clocksource(void) 97 + { 98 + #ifdef CONFIG_SMP 99 + return 0; 100 + #else 101 + return 1; 102 + #endif 103 + } 104 + 105 + /* 106 + * set 32bit TIMER1 to keep counting monotonically and wraparound 107 + */ 108 + int __cpuinit arc_counter_setup(void) 109 + { 110 + write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); 111 + write_aux_reg(ARC_REG_TIMER1_CNT, 0); 112 + write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); 113 + 114 + return is_usable_as_clocksource(); 115 + } 116 + 117 + static cycle_t arc_counter_read(struct clocksource *cs) 118 + { 119 + return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); 120 + } 121 + 122 + static struct clocksource arc_counter = { 123 + .name = "ARC Timer1", 124 + .rating = 300, 125 + .read = arc_counter_read, 126 + .mask = CLOCKSOURCE_MASK(32), 127 + .flags = CLOCK_SOURCE_IS_CONTINUOUS, 128 + }; 129 + 130 + #endif 131 + 132 + /********** Clock Event Device *********/ 133 + 134 + /* 135 + * Arm the timer to interrupt after @limit cycles 136 + * The distinction for oneshot/periodic is done in arc_event_timer_ack() below 137 + */ 138 + static void arc_timer_event_setup(unsigned int limit) 139 + { 140 + write_aux_reg(ARC_REG_TIMER0_LIMIT, limit); 141 + write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ 142 + 143 + write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); 144 + } 145 + 146 + /* 147 + * Acknowledge the interrupt (oneshot) and optionally re-arm it (periodic) 148 + * -Any write to CTRL Reg will ack the intr (NH bit: Count when not halted) 149 + * -Rearming is done by setting the IE bit 150 + * 151 + * Small optimisation: Normal code would have been 152 + * if (irq_reenable) 153 + * CTRL_REG = (IE | NH); 154 + * else 155 + * CTRL_REG = NH; 156 + * However since IE is BIT0 we can fold the branch 157 + */ 158 + static void arc_timer_event_ack(unsigned int irq_reenable) 159 + { 160 + write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); 161 + } 162 + 163 + static int arc_clkevent_set_next_event(unsigned long delta, 164 + struct clock_event_device *dev) 165 + { 166 + arc_timer_event_setup(delta); 167 + return 0; 168 + } 169 + 170 + static void arc_clkevent_set_mode(enum clock_event_mode mode, 171 + struct clock_event_device *dev) 172 + { 173 + switch (mode) { 174 + case CLOCK_EVT_MODE_PERIODIC: 175 + arc_timer_event_setup(arc_get_core_freq() / HZ); 176 + break; 177 + case CLOCK_EVT_MODE_ONESHOT: 178 + break; 179 + default: 180 + break; 181 + } 182 + 183 + return; 184 + } 185 + 186 + static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { 187 + .name = "ARC Timer0", 188 + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, 189 + .mode = CLOCK_EVT_MODE_UNUSED, 190 + .rating = 300, 191 + .irq = TIMER0_IRQ, /* hardwired, no need for resources */ 192 + .set_next_event = arc_clkevent_set_next_event, 193 + .set_mode = arc_clkevent_set_mode, 194 + }; 195 + 196 + static irqreturn_t timer_irq_handler(int irq, void *dev_id) 197 + { 198 + struct clock_event_device *clk = &__get_cpu_var(arc_clockevent_device); 199 + 200 + arc_timer_event_ack(clk->mode == CLOCK_EVT_MODE_PERIODIC); 201 + clk->event_handler(clk); 202 + return IRQ_HANDLED; 203 + } 204 + 205 + static struct irqaction arc_timer_irq = { 206 + .name = "Timer0 (clock-evt-dev)", 207 + .flags = IRQF_TIMER | IRQF_PERCPU, 208 + .handler = timer_irq_handler, 209 + }; 210 + 211 + /* 212 + * Setup the local event timer for @cpu 213 + * N.B. weak so that some exotic ARC SoCs can completely override it 214 + */ 215 + void __attribute__((weak)) __cpuinit arc_local_timer_setup(unsigned int cpu) 216 + { 217 + struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu); 218 + 219 + clockevents_calc_mult_shift(clk, arc_get_core_freq(), 5); 220 + 221 + clk->max_delta_ns = clockevent_delta2ns(ARC_TIMER_MAX, clk); 222 + clk->cpumask = cpumask_of(cpu); 223 + 224 + clockevents_register_device(clk); 225 + 226 + /* 227 + * setup the per-cpu timer IRQ handler - for all cpus 228 + * For non boot CPU explicitly unmask at intc 229 + * setup_irq() -> .. -> irq_startup() already does this on boot-cpu 230 + */ 231 + if (!cpu) 232 + setup_irq(TIMER0_IRQ, &arc_timer_irq); 233 + else 234 + arch_unmask_irq(TIMER0_IRQ); 235 + } 236 + 237 + /* 238 + * Called from start_kernel() - boot CPU only 239 + * 240 + * -Sets up h/w timers as applicable on boot cpu 241 + * -Also sets up any global state needed for timer subsystem: 242 + * - for "counting" timer, registers a clocksource, usable across CPUs 243 + * (provided that underlying counter h/w is synchronized across cores) 244 + * - for "event" timer, sets up TIMER0 IRQ (as that is platform agnostic) 245 + */ 246 + void __init time_init(void) 247 + { 248 + /* 249 + * sets up the timekeeping free-flowing counter which also returns 250 + * whether the counter is usable as clocksource 251 + */ 252 + if (arc_counter_setup()) 253 + /* 254 + * CLK upto 4.29 GHz can be safely represented in 32 bits 255 + * because Max 32 bit number is 4,294,967,295 256 + */ 257 + clocksource_register_hz(&arc_counter, arc_get_core_freq()); 258 + 259 + /* sets up the periodic event timer */ 260 + arc_local_timer_setup(smp_processor_id()); 261 + } 262 + 263 + #ifdef CONFIG_ARC_HAS_RTSC 264 + /* 265 + * sched_clock math assist 266 + * ns = cycles * (ns_per_sec / cpu_freq_hz) 267 + * ns = cycles * (10^6 / cpu_freq_khz) 268 + * ns = cycles * (10^6 * 2^SF / cpu_freq_khz) / 2^SF 269 + * ns = cycles * cyc2ns_scale >> SF 270 + */ 271 + #define CYC2NS_SF 10 /* 2^10, carefully chosen */ 272 + #define CYC2NS_SCALE ((1000000 << CYC2NS_SF) / (arc_get_core_freq() / 1000)) 273 + 274 + static unsigned long long cycles2ns(unsigned long long cyc) 275 + { 276 + return (cyc * CYC2NS_SCALE ) >> CYC2NS_SF; 277 + } 278 + 279 + /* 280 + * Scheduler clock - a monotonically increasing clock in nanosec units. 281 + * It's return value must NOT wrap around. 282 + * 283 + * - Since 32bit TIMER1 will overflow almost immediately (53sec @ 80MHz), it 284 + * can't be used directly. 285 + * - Using getrawmonotonic (TIMER1 based, but with state for last + current 286 + * snapshots), is no-good either because of seqlock deadlock possibilities 287 + * - So only with native 64bit timer we do this, otherwise fallback to generic 288 + * jiffies based version - which despite not being fine grained gaurantees 289 + * the monotonically increasing semantics. 290 + */ 291 + unsigned long long sched_clock(void) 292 + { 293 + return cycles2ns(arc_counter_read(NULL)); 294 + } 295 + #endif