aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitri Sivanich <sivanich@sgi.com>2010-10-27 18:34:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-27 21:03:14 -0400
commitdcade5ed16cce572e375bf4e63dd2150c351bf49 (patch)
tree4bd086e5976978e605277f26c9e6baab77d3df3c
parent656e17ea9d997db1bb37d90b7a447eb511af5a63 (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.c60
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 */
179static int mmtimer_setup(int cpu, int comparator, unsigned long expires) 179static 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 */
231struct mmtimer { 234struct mmtimer {
232 struct rb_node list; 235 struct rb_node list;
@@ -242,6 +245,11 @@ struct mmtimer_node {
242}; 245};
243static struct mmtimer_node *timers; 246static struct mmtimer_node *timers;
244 247
248static unsigned mmtimer_interval_retry_increment =
249 MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT;
250module_param(mmtimer_interval_retry_increment, uint, 0644);
251MODULE_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
294restart: 303restart:
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