diff options
Diffstat (limited to 'arch/arm/mach-sa1100/time.c')
-rw-r--r-- | arch/arm/mach-sa1100/time.c | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 0eeb3616ffea..47e0420623fc 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c | |||
@@ -70,15 +70,11 @@ static unsigned long sa1100_gettimeoffset (void) | |||
70 | return usec; | 70 | return usec; |
71 | } | 71 | } |
72 | 72 | ||
73 | /* | 73 | #ifdef CONFIG_NO_IDLE_HZ |
74 | * We will be entered with IRQs enabled. | 74 | static unsigned long initial_match; |
75 | * | 75 | static int match_posponed; |
76 | * Loop until we get ahead of the free running timer. | 76 | #endif |
77 | * This ensures an exact clock tick count and time accuracy. | 77 | |
78 | * IRQs are disabled inside the loop to ensure coherence between | ||
79 | * lost_ticks (updated in do_timer()) and the match reg value, so we | ||
80 | * can use do_gettimeofday() from interrupt handlers. | ||
81 | */ | ||
82 | static irqreturn_t | 78 | static irqreturn_t |
83 | sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 79 | sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
84 | { | 80 | { |
@@ -86,6 +82,21 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
86 | 82 | ||
87 | write_seqlock(&xtime_lock); | 83 | write_seqlock(&xtime_lock); |
88 | 84 | ||
85 | #ifdef CONFIG_NO_IDLE_HZ | ||
86 | if (match_posponed) { | ||
87 | match_posponed = 0; | ||
88 | OSMR0 = initial_match; | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | /* | ||
93 | * Loop until we get ahead of the free running timer. | ||
94 | * This ensures an exact clock tick count and time accuracy. | ||
95 | * Since IRQs are disabled at this point, coherence between | ||
96 | * lost_ticks(updated in do_timer()) and the match reg value is | ||
97 | * ensured, hence we can use do_gettimeofday() from interrupt | ||
98 | * handlers. | ||
99 | */ | ||
89 | do { | 100 | do { |
90 | timer_tick(regs); | 101 | timer_tick(regs); |
91 | OSSR = OSSR_M0; /* Clear match on timer 0 */ | 102 | OSSR = OSSR_M0; /* Clear match on timer 0 */ |
@@ -120,6 +131,42 @@ static void __init sa1100_timer_init(void) | |||
120 | OSCR = 0; /* initialize free-running timer, force first match */ | 131 | OSCR = 0; /* initialize free-running timer, force first match */ |
121 | } | 132 | } |
122 | 133 | ||
134 | #ifdef CONFIG_NO_IDLE_HZ | ||
135 | static int sa1100_dyn_tick_enable_disable(void) | ||
136 | { | ||
137 | /* nothing to do */ | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static void sa1100_dyn_tick_reprogram(unsigned long ticks) | ||
142 | { | ||
143 | if (ticks > 1) { | ||
144 | initial_match = OSMR0; | ||
145 | OSMR0 = initial_match + ticks * LATCH; | ||
146 | match_posponed = 1; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static irqreturn_t | ||
151 | sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
152 | { | ||
153 | if (match_posponed) { | ||
154 | match_posponed = 0; | ||
155 | OSMR0 = initial_match; | ||
156 | if ((signed long)(initial_match - OSCR) <= 0) | ||
157 | return sa1100_timer_interrupt(irq, dev_id, regs); | ||
158 | } | ||
159 | return IRQ_NONE; | ||
160 | } | ||
161 | |||
162 | static struct dyn_tick_timer sa1100_dyn_tick = { | ||
163 | .enable = sa1100_dyn_tick_enable_disable, | ||
164 | .disable = sa1100_dyn_tick_enable_disable, | ||
165 | .reprogram = sa1100_dyn_tick_reprogram, | ||
166 | .handler = sa1100_dyn_tick_handler, | ||
167 | }; | ||
168 | #endif | ||
169 | |||
123 | #ifdef CONFIG_PM | 170 | #ifdef CONFIG_PM |
124 | unsigned long osmr[4], oier; | 171 | unsigned long osmr[4], oier; |
125 | 172 | ||
@@ -156,4 +203,7 @@ struct sys_timer sa1100_timer = { | |||
156 | .suspend = sa1100_timer_suspend, | 203 | .suspend = sa1100_timer_suspend, |
157 | .resume = sa1100_timer_resume, | 204 | .resume = sa1100_timer_resume, |
158 | .offset = sa1100_gettimeoffset, | 205 | .offset = sa1100_gettimeoffset, |
206 | #ifdef CONFIG_NO_IDLE_HZ | ||
207 | .dyn_tick = &sa1100_dyn_tick, | ||
208 | #endif | ||
159 | }; | 209 | }; |