Commit dcade5ed authored by Dimitri Sivanich's avatar Dimitri Sivanich Committed by Linus Torvalds

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: default avatarDimitri Sivanich <sivanich@sgi.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 656e17ea
...@@ -176,9 +176,9 @@ static void mmtimer_setup_int_2(int cpu, u64 expires) ...@@ -176,9 +176,9 @@ static void mmtimer_setup_int_2(int cpu, u64 expires)
* in order to insure that the setup succeeds in a deterministic time frame. * in order to insure that the setup succeeds in a deterministic time frame.
* It will check if the interrupt setup succeeded. * It will check if the interrupt setup succeeded.
*/ */
static int mmtimer_setup(int cpu, int comparator, unsigned long expires) static int mmtimer_setup(int cpu, int comparator, unsigned long expires,
u64 *set_completion_time)
{ {
switch (comparator) { switch (comparator) {
case 0: case 0:
mmtimer_setup_int_0(cpu, expires); mmtimer_setup_int_0(cpu, expires);
...@@ -191,7 +191,8 @@ static int mmtimer_setup(int cpu, int comparator, unsigned long expires) ...@@ -191,7 +191,8 @@ static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
break; break;
} }
/* We might've missed our expiration time */ /* We might've missed our expiration time */
if (rtc_time() <= expires) *set_completion_time = rtc_time();
if (*set_completion_time <= expires)
return 1; return 1;
/* /*
...@@ -227,6 +228,8 @@ static int mmtimer_disable_int(long nasid, int comparator) ...@@ -227,6 +228,8 @@ static int mmtimer_disable_int(long nasid, int comparator)
#define TIMER_OFF 0xbadcabLL /* Timer is not setup */ #define TIMER_OFF 0xbadcabLL /* Timer is not setup */
#define TIMER_SET 0 /* Comparator is set for this timer */ #define TIMER_SET 0 /* Comparator is set for this timer */
#define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40
/* There is one of these for each timer */ /* There is one of these for each timer */
struct mmtimer { struct mmtimer {
struct rb_node list; struct rb_node list;
...@@ -242,6 +245,11 @@ struct mmtimer_node { ...@@ -242,6 +245,11 @@ struct mmtimer_node {
}; };
static struct mmtimer_node *timers; static struct mmtimer_node *timers;
static unsigned mmtimer_interval_retry_increment =
MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT;
module_param(mmtimer_interval_retry_increment, uint, 0644);
MODULE_PARM_DESC(mmtimer_interval_retry_increment,
"RTC ticks to add to expiration on interval retry (default 40)");
/* /*
* Add a new mmtimer struct to the node's mmtimer list. * Add a new mmtimer struct to the node's mmtimer list.
...@@ -289,7 +297,8 @@ static void mmtimer_set_next_timer(int nodeid) ...@@ -289,7 +297,8 @@ static void mmtimer_set_next_timer(int nodeid)
struct mmtimer_node *n = &timers[nodeid]; struct mmtimer_node *n = &timers[nodeid];
struct mmtimer *x; struct mmtimer *x;
struct k_itimer *t; struct k_itimer *t;
int o; u64 expires, exp, set_completion_time;
int i;
restart: restart:
if (n->next == NULL) if (n->next == NULL)
...@@ -300,7 +309,8 @@ static void mmtimer_set_next_timer(int nodeid) ...@@ -300,7 +309,8 @@ static void mmtimer_set_next_timer(int nodeid)
if (!t->it.mmtimer.incr) { if (!t->it.mmtimer.incr) {
/* Not an interval timer */ /* Not an interval timer */
if (!mmtimer_setup(x->cpu, COMPARATOR, if (!mmtimer_setup(x->cpu, COMPARATOR,
t->it.mmtimer.expires)) { t->it.mmtimer.expires,
&set_completion_time)) {
/* Late setup, fire now */ /* Late setup, fire now */
tasklet_schedule(&n->tasklet); tasklet_schedule(&n->tasklet);
} }
...@@ -308,14 +318,23 @@ static void mmtimer_set_next_timer(int nodeid) ...@@ -308,14 +318,23 @@ static void mmtimer_set_next_timer(int nodeid)
} }
/* Interval timer */ /* Interval timer */
o = 0; i = 0;
while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) { expires = exp = t->it.mmtimer.expires;
unsigned long e, e1; while (!mmtimer_setup(x->cpu, COMPARATOR, expires,
struct rb_node *next; &set_completion_time)) {
t->it.mmtimer.expires += t->it.mmtimer.incr << o; int to;
t->it_overrun += 1 << o;
o++; i++;
if (o > 20) { expires = set_completion_time +
mmtimer_interval_retry_increment + (1 << i);
/* Calculate overruns as we go. */
to = ((u64)(expires - exp) / t->it.mmtimer.incr);
if (to) {
t->it_overrun += to;
t->it.mmtimer.expires += t->it.mmtimer.incr * to;
exp = t->it.mmtimer.expires;
}
if (i > 20) {
printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); printk(KERN_ALERT "mmtimer: cannot reschedule timer\n");
t->it.mmtimer.clock = TIMER_OFF; t->it.mmtimer.clock = TIMER_OFF;
n->next = rb_next(&x->list); n->next = rb_next(&x->list);
...@@ -323,21 +342,6 @@ static void mmtimer_set_next_timer(int nodeid) ...@@ -323,21 +342,6 @@ static void mmtimer_set_next_timer(int nodeid)
kfree(x); kfree(x);
goto restart; goto restart;
} }
e = t->it.mmtimer.expires;
next = rb_next(&x->list);
if (next == NULL)
continue;
e1 = rb_entry(next, struct mmtimer, list)->
timer->it.mmtimer.expires;
if (e > e1) {
n->next = next;
rb_erase(&x->list, &n->timer_head);
mmtimer_add_list(x);
goto restart;
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment