diff options
-rw-r--r-- | arch/arm/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-pxa/time.c | 51 |
2 files changed, 53 insertions, 2 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4bf0e8737e1f..dc0fafc7f9bd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -365,8 +365,8 @@ config NO_IDLE_HZ | |||
365 | 365 | ||
366 | Please note that dynamic tick may affect the accuracy of | 366 | Please note that dynamic tick may affect the accuracy of |
367 | timekeeping on some platforms depending on the implementation. | 367 | timekeeping on some platforms depending on the implementation. |
368 | Currently at least OMAP platform is known to have accurate | 368 | Currently at least OMAP and PXA2xx platforms are known to have |
369 | timekeeping with dynamic tick. | 369 | accurate timekeeping with dynamic tick. |
370 | 370 | ||
371 | config ARCH_DISCONTIGMEM_ENABLE | 371 | config ARCH_DISCONTIGMEM_ENABLE |
372 | bool | 372 | bool |
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 6e5202154f91..72b15e9a373a 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c | |||
@@ -70,6 +70,11 @@ static unsigned long pxa_gettimeoffset (void) | |||
70 | return usec; | 70 | return usec; |
71 | } | 71 | } |
72 | 72 | ||
73 | #ifdef CONFIG_NO_IDLE_HZ | ||
74 | static unsigned long initial_match; | ||
75 | static int match_posponed; | ||
76 | #endif | ||
77 | |||
73 | static irqreturn_t | 78 | static irqreturn_t |
74 | pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 79 | pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
75 | { | 80 | { |
@@ -77,6 +82,13 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
77 | 82 | ||
78 | write_seqlock(&xtime_lock); | 83 | write_seqlock(&xtime_lock); |
79 | 84 | ||
85 | #ifdef CONFIG_NO_IDLE_HZ | ||
86 | if (match_posponed) { | ||
87 | match_posponed = 0; | ||
88 | OSMR0 = initial_match; | ||
89 | } | ||
90 | #endif | ||
91 | |||
80 | /* Loop until we get ahead of the free running timer. | 92 | /* Loop until we get ahead of the free running timer. |
81 | * This ensures an exact clock tick count and time accuracy. | 93 | * This ensures an exact clock tick count and time accuracy. |
82 | * IRQs are disabled inside the loop to ensure coherence between | 94 | * IRQs are disabled inside the loop to ensure coherence between |
@@ -126,6 +138,42 @@ static void __init pxa_timer_init(void) | |||
126 | OSCR = 0; /* initialize free-running timer, force first match */ | 138 | OSCR = 0; /* initialize free-running timer, force first match */ |
127 | } | 139 | } |
128 | 140 | ||
141 | #ifdef CONFIG_NO_IDLE_HZ | ||
142 | static int pxa_dyn_tick_enable_disable(void) | ||
143 | { | ||
144 | /* nothing to do */ | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static void pxa_dyn_tick_reprogram(unsigned long ticks) | ||
149 | { | ||
150 | if (ticks > 1) { | ||
151 | initial_match = OSMR0; | ||
152 | OSMR0 = initial_match + ticks * LATCH; | ||
153 | match_posponed = 1; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static irqreturn_t | ||
158 | pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
159 | { | ||
160 | if (match_posponed) { | ||
161 | match_posponed = 0; | ||
162 | OSMR0 = initial_match; | ||
163 | if ( (signed long)(initial_match - OSCR) <= 8 ) | ||
164 | return pxa_timer_interrupt(irq, dev_id, regs); | ||
165 | } | ||
166 | return IRQ_NONE; | ||
167 | } | ||
168 | |||
169 | static struct dyn_tick_timer pxa_dyn_tick = { | ||
170 | .enable = pxa_dyn_tick_enable_disable, | ||
171 | .disable = pxa_dyn_tick_enable_disable, | ||
172 | .reprogram = pxa_dyn_tick_reprogram, | ||
173 | .handler = pxa_dyn_tick_handler, | ||
174 | }; | ||
175 | #endif | ||
176 | |||
129 | #ifdef CONFIG_PM | 177 | #ifdef CONFIG_PM |
130 | static unsigned long osmr[4], oier; | 178 | static unsigned long osmr[4], oier; |
131 | 179 | ||
@@ -161,4 +209,7 @@ struct sys_timer pxa_timer = { | |||
161 | .suspend = pxa_timer_suspend, | 209 | .suspend = pxa_timer_suspend, |
162 | .resume = pxa_timer_resume, | 210 | .resume = pxa_timer_resume, |
163 | .offset = pxa_gettimeoffset, | 211 | .offset = pxa_gettimeoffset, |
212 | #ifdef CONFIG_NO_IDLE_HZ | ||
213 | .dyn_tick = &pxa_dyn_tick, | ||
214 | #endif | ||
164 | }; | 215 | }; |