Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dimitri Sivanich and committed by
Linus Torvalds
dcade5ed 656e17ea

+32 -28
+32 -28
drivers/char/mmtimer.c
··· 176 176 * in order to insure that the setup succeeds in a deterministic time frame. 177 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 182 switch (comparator) { 183 183 case 0: 184 184 mmtimer_setup_int_0(cpu, expires); ··· 191 191 break; 192 192 } 193 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 196 return 1; 196 197 197 198 /* ··· 228 227 #define TIMER_OFF 0xbadcabLL /* Timer is not setup */ 229 228 #define TIMER_SET 0 /* Comparator is set for this timer */ 230 229 230 + #define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40 231 + 231 232 /* There is one of these for each timer */ 232 233 struct mmtimer { 233 234 struct rb_node list; ··· 245 242 }; 246 243 static struct mmtimer_node *timers; 247 244 245 + static unsigned mmtimer_interval_retry_increment = 246 + MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT; 247 + module_param(mmtimer_interval_retry_increment, uint, 0644); 248 + MODULE_PARM_DESC(mmtimer_interval_retry_increment, 249 + "RTC ticks to add to expiration on interval retry (default 40)"); 248 250 249 251 /* 250 252 * Add a new mmtimer struct to the node's mmtimer list. ··· 297 289 struct mmtimer_node *n = &timers[nodeid]; 298 290 struct mmtimer *x; 299 291 struct k_itimer *t; 300 - int o; 292 + u64 expires, exp, set_completion_time; 293 + int i; 301 294 302 295 restart: 303 296 if (n->next == NULL) ··· 309 300 if (!t->it.mmtimer.incr) { 310 301 /* Not an interval timer */ 311 302 if (!mmtimer_setup(x->cpu, COMPARATOR, 312 - t->it.mmtimer.expires)) { 303 + t->it.mmtimer.expires, 304 + &set_completion_time)) { 313 305 /* Late setup, fire now */ 314 306 tasklet_schedule(&n->tasklet); 315 307 } ··· 318 308 } 319 309 320 310 /* Interval timer */ 321 - o = 0; 322 - while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) { 323 - unsigned long e, e1; 324 - struct rb_node *next; 325 - t->it.mmtimer.expires += t->it.mmtimer.incr << o; 326 - t->it_overrun += 1 << o; 327 - o++; 328 - if (o > 20) { 311 + i = 0; 312 + expires = exp = t->it.mmtimer.expires; 313 + while (!mmtimer_setup(x->cpu, COMPARATOR, expires, 314 + &set_completion_time)) { 315 + int to; 316 + 317 + i++; 318 + expires = set_completion_time + 319 + mmtimer_interval_retry_increment + (1 << i); 320 + /* Calculate overruns as we go. */ 321 + to = ((u64)(expires - exp) / t->it.mmtimer.incr); 322 + if (to) { 323 + t->it_overrun += to; 324 + t->it.mmtimer.expires += t->it.mmtimer.incr * to; 325 + exp = t->it.mmtimer.expires; 326 + } 327 + if (i > 20) { 329 328 printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); 330 329 t->it.mmtimer.clock = TIMER_OFF; 331 330 n->next = rb_next(&x->list); 332 331 rb_erase(&x->list, &n->timer_head); 333 332 kfree(x); 334 - goto restart; 335 - } 336 - 337 - e = t->it.mmtimer.expires; 338 - next = rb_next(&x->list); 339 - 340 - if (next == NULL) 341 - continue; 342 - 343 - e1 = rb_entry(next, struct mmtimer, list)-> 344 - timer->it.mmtimer.expires; 345 - if (e > e1) { 346 - n->next = next; 347 - rb_erase(&x->list, &n->timer_head); 348 - mmtimer_add_list(x); 349 333 goto restart; 350 334 } 351 335 }