diff options
author | Dimitri Sivanich <sivanich@sgi.com> | 2010-10-27 18:34:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:03:14 -0400 |
commit | dcade5ed16cce572e375bf4e63dd2150c351bf49 (patch) | |
tree | 4bd086e5976978e605277f26c9e6baab77d3df3c | |
parent | 656e17ea9d997db1bb37d90b7a447eb511af5a63 (diff) |
SGI Altix IA64 mmtimer: eliminate long interval timer holdoffs
This patch for SGI Altix/IA64 eliminates interval long timer holdoffs in
cases where we don't start an interval timer before the expiration time.
This sometimes happens when a number of interval timers on the same shub
with the same interval run simultaneously.
Signed-off-by: Dimitri Sivanich <sivanich@sgi.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/char/mmtimer.c | 60 |
1 files changed, 32 insertions, 28 deletions
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index c070b53984e4..e6d75627c6c8 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c | |||
@@ -176,9 +176,9 @@ static void mmtimer_setup_int_2(int cpu, u64 expires) | |||
176 | * in order to insure that the setup succeeds in a deterministic time frame. | 176 | * in order to insure that the setup succeeds in a deterministic time frame. |
177 | * It will check if the interrupt setup succeeded. | 177 | * It will check if the interrupt setup succeeded. |
178 | */ | 178 | */ |
179 | static int mmtimer_setup(int cpu, int comparator, unsigned long expires) | 179 | static int mmtimer_setup(int cpu, int comparator, unsigned long expires, |
180 | u64 *set_completion_time) | ||
180 | { | 181 | { |
181 | |||
182 | switch (comparator) { | 182 | switch (comparator) { |
183 | case 0: | 183 | case 0: |
184 | mmtimer_setup_int_0(cpu, expires); | 184 | mmtimer_setup_int_0(cpu, expires); |
@@ -191,7 +191,8 @@ static int mmtimer_setup(int cpu, int comparator, unsigned long expires) | |||
191 | break; | 191 | break; |
192 | } | 192 | } |
193 | /* We might've missed our expiration time */ | 193 | /* We might've missed our expiration time */ |
194 | if (rtc_time() <= expires) | 194 | *set_completion_time = rtc_time(); |
195 | if (*set_completion_time <= expires) | ||
195 | return 1; | 196 | return 1; |
196 | 197 | ||
197 | /* | 198 | /* |
@@ -227,6 +228,8 @@ static int mmtimer_disable_int(long nasid, int comparator) | |||
227 | #define TIMER_OFF 0xbadcabLL /* Timer is not setup */ | 228 | #define TIMER_OFF 0xbadcabLL /* Timer is not setup */ |
228 | #define TIMER_SET 0 /* Comparator is set for this timer */ | 229 | #define TIMER_SET 0 /* Comparator is set for this timer */ |
229 | 230 | ||
231 | #define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40 | ||
232 | |||
230 | /* There is one of these for each timer */ | 233 | /* There is one of these for each timer */ |
231 | struct mmtimer { | 234 | struct mmtimer { |
232 | struct rb_node list; | 235 | struct rb_node list; |
@@ -242,6 +245,11 @@ struct mmtimer_node { | |||
242 | }; | 245 | }; |
243 | static struct mmtimer_node *timers; | 246 | static struct mmtimer_node *timers; |
244 | 247 | ||
248 | static unsigned mmtimer_interval_retry_increment = | ||
249 | MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT; | ||
250 | module_param(mmtimer_interval_retry_increment, uint, 0644); | ||
251 | MODULE_PARM_DESC(mmtimer_interval_retry_increment, | ||
252 | "RTC ticks to add to expiration on interval retry (default 40)"); | ||
245 | 253 | ||
246 | /* | 254 | /* |
247 | * Add a new mmtimer struct to the node's mmtimer list. | 255 | * Add a new mmtimer struct to the node's mmtimer list. |
@@ -289,7 +297,8 @@ static void mmtimer_set_next_timer(int nodeid) | |||
289 | struct mmtimer_node *n = &timers[nodeid]; | 297 | struct mmtimer_node *n = &timers[nodeid]; |
290 | struct mmtimer *x; | 298 | struct mmtimer *x; |
291 | struct k_itimer *t; | 299 | struct k_itimer *t; |
292 | int o; | 300 | u64 expires, exp, set_completion_time; |
301 | int i; | ||
293 | 302 | ||
294 | restart: | 303 | restart: |
295 | if (n->next == NULL) | 304 | if (n->next == NULL) |
@@ -300,7 +309,8 @@ restart: | |||
300 | if (!t->it.mmtimer.incr) { | 309 | if (!t->it.mmtimer.incr) { |
301 | /* Not an interval timer */ | 310 | /* Not an interval timer */ |
302 | if (!mmtimer_setup(x->cpu, COMPARATOR, | 311 | if (!mmtimer_setup(x->cpu, COMPARATOR, |
303 | t->it.mmtimer.expires)) { | 312 | t->it.mmtimer.expires, |
313 | &set_completion_time)) { | ||
304 | /* Late setup, fire now */ | 314 | /* Late setup, fire now */ |
305 | tasklet_schedule(&n->tasklet); | 315 | tasklet_schedule(&n->tasklet); |
306 | } | 316 | } |
@@ -308,14 +318,23 @@ restart: | |||
308 | } | 318 | } |
309 | 319 | ||
310 | /* Interval timer */ | 320 | /* Interval timer */ |
311 | o = 0; | 321 | i = 0; |
312 | while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) { | 322 | expires = exp = t->it.mmtimer.expires; |
313 | unsigned long e, e1; | 323 | while (!mmtimer_setup(x->cpu, COMPARATOR, expires, |
314 | struct rb_node *next; | 324 | &set_completion_time)) { |
315 | t->it.mmtimer.expires += t->it.mmtimer.incr << o; | 325 | int to; |
316 | t->it_overrun += 1 << o; | 326 | |
317 | o++; | 327 | i++; |
318 | if (o > 20) { | 328 | expires = set_completion_time + |
329 | mmtimer_interval_retry_increment + (1 << i); | ||
330 | /* Calculate overruns as we go. */ | ||
331 | to = ((u64)(expires - exp) / t->it.mmtimer.incr); | ||
332 | if (to) { | ||
333 | t->it_overrun += to; | ||
334 | t->it.mmtimer.expires += t->it.mmtimer.incr * to; | ||
335 | exp = t->it.mmtimer.expires; | ||
336 | } | ||
337 | if (i > 20) { | ||
319 | printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); | 338 | printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); |
320 | t->it.mmtimer.clock = TIMER_OFF; | 339 | t->it.mmtimer.clock = TIMER_OFF; |
321 | n->next = rb_next(&x->list); | 340 | n->next = rb_next(&x->list); |
@@ -323,21 +342,6 @@ restart: | |||
323 | kfree(x); | 342 | kfree(x); |
324 | goto restart; | 343 | goto restart; |
325 | } | 344 | } |
326 | |||
327 | e = t->it.mmtimer.expires; | ||
328 | next = rb_next(&x->list); | ||
329 | |||
330 | if (next == NULL) | ||
331 | continue; | ||
332 | |||
333 | e1 = rb_entry(next, struct mmtimer, list)-> | ||
334 | timer->it.mmtimer.expires; | ||
335 | if (e > e1) { | ||
336 | n->next = next; | ||
337 | rb_erase(&x->list, &n->timer_head); | ||
338 | mmtimer_add_list(x); | ||
339 | goto restart; | ||
340 | } | ||
341 | } | 345 | } |
342 | } | 346 | } |
343 | 347 | ||