diff options
Diffstat (limited to 'drivers/char/mmtimer.c')
| -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 | ||
