aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJesper Nilsson <jesper.nilsson@axis.com>2010-07-30 11:33:07 -0400
committerJesper Nilsson <jesper.nilsson@axis.com>2010-08-04 06:58:55 -0400
commit60dbd6633178a8625ed71329da0167c6d50c559c (patch)
treebcbc1004dfe356ce7cf30f183725dbbc9dad3e4f /arch
parent26bfeea38a4a5daf52c8f01c986ca8680bf1f6a1 (diff)
CRIS: GENERIC_TIME fixes
GENERIC_TIME was not functional for CRIS, giving random backward time jumps. For CRISv32 implement a new clocksource using the free running counter and ditch the arch_gettimeoffset. The random time jumps still existed, but turned out to be the write_seqlock which was missing around our do_timer() call. So switch over to GENERIC_TIME using the clocksource for CRISv32. CRISv10 doesn't have the free running counter needed for the clocksource trick, but we can still use GENERIC_TIME with arch_gettimeoffset. Unfortunately, there were problems in using the prescaler register to timer0 for the gettimeoffset calculation, so it is now ignored, making our resolution worse by the tune of 40usec (0.4%) worst case. At the same time, clean up some formatting and use NSEC_PER_SEC instead of 1000000000. Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/cris/Kconfig5
-rw-r--r--arch/cris/arch-v10/kernel/time.c54
-rw-r--r--arch/cris/arch-v32/kernel/time.c85
-rw-r--r--arch/cris/kernel/time.c7
4 files changed, 45 insertions, 106 deletions
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index e25bf4440b51..4827c72b9634 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -27,7 +27,7 @@ config GENERIC_CMOS_UPDATE
27 def_bool y 27 def_bool y
28 28
29config ARCH_USES_GETTIMEOFFSET 29config ARCH_USES_GETTIMEOFFSET
30 def_bool y 30 def_bool n
31 31
32config GENERIC_IOMAP 32config GENERIC_IOMAP
33 bool 33 bool
@@ -131,16 +131,19 @@ choice
131 131
132config ETRAX100LX 132config ETRAX100LX
133 bool "ETRAX-100LX-v1" 133 bool "ETRAX-100LX-v1"
134 select ARCH_USES_GETTIMEOFFSET
134 help 135 help
135 Support version 1 of the ETRAX 100LX. 136 Support version 1 of the ETRAX 100LX.
136 137
137config ETRAX100LX_V2 138config ETRAX100LX_V2
138 bool "ETRAX-100LX-v2" 139 bool "ETRAX-100LX-v2"
140 select ARCH_USES_GETTIMEOFFSET
139 help 141 help
140 Support version 2 of the ETRAX 100LX. 142 Support version 2 of the ETRAX 100LX.
141 143
142config SVINTO_SIM 144config SVINTO_SIM
143 bool "ETRAX-100LX-for-xsim-simulator" 145 bool "ETRAX-100LX-for-xsim-simulator"
146 select ARCH_USES_GETTIMEOFFSET
144 help 147 help
145 Support the xsim ETRAX Simulator. 148 Support the xsim ETRAX Simulator.
146 149
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
index 30adae594aef..00eb36f8debf 100644
--- a/arch/cris/arch-v10/kernel/time.c
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -61,66 +61,16 @@ unsigned long get_ns_in_jiffie(void)
61 61
62unsigned long do_slow_gettimeoffset(void) 62unsigned long do_slow_gettimeoffset(void)
63{ 63{
64 unsigned long count, t1; 64 unsigned long count;
65 unsigned long usec_count = 0;
66 unsigned short presc_count;
67
68 static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
69 static unsigned long jiffies_p = 0;
70
71 /*
72 * cache volatile jiffies temporarily; we have IRQs turned off.
73 */
74 unsigned long jiffies_t;
75 65
76 /* The timer interrupt comes from Etrax timer 0. In order to get 66 /* The timer interrupt comes from Etrax timer 0. In order to get
77 * better precision, we check the current value. It might have 67 * better precision, we check the current value. It might have
78 * underflowed already though. 68 * underflowed already though.
79 */ 69 */
80
81#ifndef CONFIG_SVINTO_SIM
82 /* Not available in the xsim simulator. */
83 count = *R_TIMER0_DATA; 70 count = *R_TIMER0_DATA;
84 presc_count = *R_TIM_PRESC_STATUS;
85 /* presc_count might be wrapped */
86 t1 = *R_TIMER0_DATA;
87 if (count != t1){
88 /* it wrapped, read prescaler again... */
89 presc_count = *R_TIM_PRESC_STATUS;
90 count = t1;
91 }
92#else
93 count = 0;
94 presc_count = 0;
95#endif
96
97 jiffies_t = jiffies;
98 71
99 /*
100 * avoiding timer inconsistencies (they are rare, but they happen)...
101 * there are one problem that must be avoided here:
102 * 1. the timer counter underflows
103 */
104 if( jiffies_t == jiffies_p ) {
105 if( count > count_p ) {
106 /* Timer wrapped, use new count and prescale
107 * increase the time corresponding to one jiffie
108 */
109 usec_count = 1000000/HZ;
110 }
111 } else
112 jiffies_p = jiffies_t;
113 count_p = count;
114 if (presc_count >= PRESCALE_VALUE/2 ){
115 presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2;
116 } else {
117 presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
118 }
119 /* Convert timer value to usec */ 72 /* Convert timer value to usec */
120 usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) + 73 return (TIMER0_DIV - count) * ((NSEC_PER_SEC/1000)/HZ)/TIMER0_DIV;
121 (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000);
122
123 return usec_count;
124} 74}
125 75
126/* Excerpt from the Etrax100 HSDD about the built-in watchdog: 76/* Excerpt from the Etrax100 HSDD about the built-in watchdog:
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index 1ee0e1010228..a545211e999d 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -1,13 +1,13 @@
1/* 1/*
2 * linux/arch/cris/arch-v32/kernel/time.c 2 * linux/arch/cris/arch-v32/kernel/time.c
3 * 3 *
4 * Copyright (C) 2003-2007 Axis Communications AB 4 * Copyright (C) 2003-2010 Axis Communications AB
5 * 5 *
6 */ 6 */
7 7
8#include <linux/timex.h> 8#include <linux/timex.h>
9#include <linux/time.h> 9#include <linux/time.h>
10#include <linux/jiffies.h> 10#include <linux/clocksource.h>
11#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <linux/swap.h> 12#include <linux/swap.h>
13#include <linux/sched.h> 13#include <linux/sched.h>
@@ -36,6 +36,30 @@
36/* Number of 763 counts before watchdog bites */ 36/* Number of 763 counts before watchdog bites */
37#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) 37#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1)
38 38
39/* Register the continuos readonly timer available in FS and ARTPEC-3. */
40static cycle_t read_cont_rotime(struct clocksource *cs)
41{
42 return (u32)REG_RD(timer, regi_timer0, r_time);
43}
44
45static struct clocksource cont_rotime = {
46 .name = "crisv32_rotime",
47 .rating = 300,
48 .read = read_cont_rotime,
49 .mask = CLOCKSOURCE_MASK(32),
50 .shift = 10,
51 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
52};
53
54static int __init etrax_init_cont_rotime(void)
55{
56 cont_rotime.mult = clocksource_khz2mult(100000, cont_rotime.shift);
57 clocksource_register(&cont_rotime);
58 return 0;
59}
60arch_initcall(etrax_init_cont_rotime);
61
62
39unsigned long timer_regs[NR_CPUS] = 63unsigned long timer_regs[NR_CPUS] =
40{ 64{
41 regi_timer0, 65 regi_timer0,
@@ -67,43 +91,6 @@ unsigned long get_ns_in_jiffie(void)
67 return ns; 91 return ns;
68} 92}
69 93
70unsigned long do_slow_gettimeoffset(void)
71{
72 unsigned long count;
73 unsigned long usec_count = 0;
74
75 /* For the first call after boot */
76 static unsigned long count_p = TIMER0_DIV;
77 static unsigned long jiffies_p = 0;
78
79 /* Cache volatile jiffies temporarily; we have IRQs turned off. */
80 unsigned long jiffies_t;
81
82 /* The timer interrupt comes from Etrax timer 0. In order to get
83 * better precision, we check the current value. It might have
84 * underflowed already though. */
85 count = REG_RD(timer, regi_timer0, r_tmr0_data);
86 jiffies_t = jiffies;
87
88 /* Avoiding timer inconsistencies (they are rare, but they happen)
89 * There is one problem that must be avoided here:
90 * 1. the timer counter underflows
91 */
92 if( jiffies_t == jiffies_p ) {
93 if( count > count_p ) {
94 /* Timer wrapped, use new count and prescale.
95 * Increase the time corresponding to one jiffy.
96 */
97 usec_count = 1000000/HZ;
98 }
99 } else
100 jiffies_p = jiffies_t;
101 count_p = count;
102 /* Convert timer value to usec */
103 /* 100 MHz timer, divide by 100 to get usec */
104 usec_count += (TIMER0_DIV - count) / 100;
105 return usec_count;
106}
107 94
108/* From timer MDS describing the hardware watchdog: 95/* From timer MDS describing the hardware watchdog:
109 * 4.3.1 Watchdog Operation 96 * 4.3.1 Watchdog Operation
@@ -126,8 +113,7 @@ static short int watchdog_key = 42; /* arbitrary 7 bit number */
126 * is used though, so set this really low. */ 113 * is used though, so set this really low. */
127#define WATCHDOG_MIN_FREE_PAGES 8 114#define WATCHDOG_MIN_FREE_PAGES 8
128 115
129void 116void reset_watchdog(void)
130reset_watchdog(void)
131{ 117{
132#if defined(CONFIG_ETRAX_WATCHDOG) 118#if defined(CONFIG_ETRAX_WATCHDOG)
133 reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; 119 reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
@@ -147,8 +133,7 @@ reset_watchdog(void)
147 133
148/* stop the watchdog - we still need the correct key */ 134/* stop the watchdog - we still need the correct key */
149 135
150void 136void stop_watchdog(void)
151stop_watchdog(void)
152{ 137{
153#if defined(CONFIG_ETRAX_WATCHDOG) 138#if defined(CONFIG_ETRAX_WATCHDOG)
154 reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; 139 reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
@@ -162,8 +147,7 @@ stop_watchdog(void)
162 147
163extern void show_registers(struct pt_regs *regs); 148extern void show_registers(struct pt_regs *regs);
164 149
165void 150void handle_watchdog_bite(struct pt_regs *regs)
166handle_watchdog_bite(struct pt_regs* regs)
167{ 151{
168#if defined(CONFIG_ETRAX_WATCHDOG) 152#if defined(CONFIG_ETRAX_WATCHDOG)
169 extern int cause_of_death; 153 extern int cause_of_death;
@@ -203,8 +187,7 @@ handle_watchdog_bite(struct pt_regs* regs)
203 */ 187 */
204extern void cris_do_profile(struct pt_regs *regs); 188extern void cris_do_profile(struct pt_regs *regs);
205 189
206static inline irqreturn_t 190static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
207timer_interrupt(int irq, void *dev_id)
208{ 191{
209 struct pt_regs *regs = get_irq_regs(); 192 struct pt_regs *regs = get_irq_regs();
210 int cpu = smp_processor_id(); 193 int cpu = smp_processor_id();
@@ -233,7 +216,9 @@ timer_interrupt(int irq, void *dev_id)
233 return IRQ_HANDLED; 216 return IRQ_HANDLED;
234 217
235 /* Call the real timer interrupt handler */ 218 /* Call the real timer interrupt handler */
219 write_seqlock(&xtime_lock);
236 do_timer(1); 220 do_timer(1);
221 write_sequnlock(&xtime_lock);
237 return IRQ_HANDLED; 222 return IRQ_HANDLED;
238} 223}
239 224
@@ -246,8 +231,7 @@ static struct irqaction irq_timer = {
246 .name = "timer" 231 .name = "timer"
247}; 232};
248 233
249void __init 234void __init cris_timer_init(void)
250cris_timer_init(void)
251{ 235{
252 int cpu = smp_processor_id(); 236 int cpu = smp_processor_id();
253 reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; 237 reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
@@ -273,8 +257,7 @@ cris_timer_init(void)
273 REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); 257 REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
274} 258}
275 259
276void __init 260void __init time_init(void)
277time_init(void)
278{ 261{
279 reg_intr_vect_rw_mask intr_mask; 262 reg_intr_vect_rw_mask intr_mask;
280 263
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
index c72730d20ef6..b5096430ce1c 100644
--- a/arch/cris/kernel/time.c
+++ b/arch/cris/kernel/time.c
@@ -39,13 +39,16 @@ int have_rtc; /* used to remember if we have an RTC or not */;
39extern unsigned long loops_per_jiffy; /* init/main.c */ 39extern unsigned long loops_per_jiffy; /* init/main.c */
40unsigned long loops_per_usec; 40unsigned long loops_per_usec;
41 41
42
43#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
42extern unsigned long do_slow_gettimeoffset(void); 44extern unsigned long do_slow_gettimeoffset(void);
43static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; 45static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
44 46
45u32 arch_gettimeoffset(void) 47u32 arch_gettimeoffset(void)
46{ 48{
47 return do_gettimeoffset() * 1000; 49 return do_gettimeoffset() * 1000;
48} 50}
51#endif
49 52
50/* 53/*
51 * BUG: This routine does not handle hour overflow properly; it just 54 * BUG: This routine does not handle hour overflow properly; it just
@@ -151,7 +154,7 @@ cris_do_profile(struct pt_regs* regs)
151 154
152unsigned long long sched_clock(void) 155unsigned long long sched_clock(void)
153{ 156{
154 return (unsigned long long)jiffies * (1000000000 / HZ) + 157 return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ) +
155 get_ns_in_jiffie(); 158 get_ns_in_jiffie();
156} 159}
157 160