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>
This commit is contained in:
parent
656e17ea9d
commit
dcade5ed16
1 changed files with 32 additions and 28 deletions
|
@ -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)
|
||||||
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)
|
||||||
#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 {
|
||||||
};
|
};
|
||||||
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)
|
||||||
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 @@ restart:
|
||||||
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 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 @@ restart:
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue