diff options
| -rw-r--r-- | include/linux/clocksource.h | 2 | ||||
| -rw-r--r-- | kernel/time/clocksource.c | 112 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 41 |
3 files changed, 72 insertions, 83 deletions
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index e34015effeb6..9ea40ff26f0e 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
| @@ -291,4 +291,6 @@ static inline void update_vsyscall_tz(void) | |||
| 291 | } | 291 | } |
| 292 | #endif | 292 | #endif |
| 293 | 293 | ||
| 294 | extern void timekeeping_notify(struct clocksource *clock); | ||
| 295 | |||
| 294 | #endif /* _LINUX_CLOCKSOURCE_H */ | 296 | #endif /* _LINUX_CLOCKSOURCE_H */ |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index f18c9a6bdcf4..a1657b5fdeb9 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
| @@ -109,35 +109,17 @@ EXPORT_SYMBOL(timecounter_cyc2time); | |||
| 109 | /*[Clocksource internal variables]--------- | 109 | /*[Clocksource internal variables]--------- |
| 110 | * curr_clocksource: | 110 | * curr_clocksource: |
| 111 | * currently selected clocksource. | 111 | * currently selected clocksource. |
| 112 | * next_clocksource: | ||
| 113 | * pending next selected clocksource. | ||
| 114 | * clocksource_list: | 112 | * clocksource_list: |
| 115 | * linked list with the registered clocksources | 113 | * linked list with the registered clocksources |
| 116 | * clocksource_lock: | 114 | * clocksource_mutex: |
| 117 | * protects manipulations to curr_clocksource and next_clocksource | 115 | * protects manipulations to curr_clocksource and the clocksource_list |
| 118 | * and the clocksource_list | ||
| 119 | * override_name: | 116 | * override_name: |
| 120 | * Name of the user-specified clocksource. | 117 | * Name of the user-specified clocksource. |
| 121 | */ | 118 | */ |
| 122 | static struct clocksource *curr_clocksource; | 119 | static struct clocksource *curr_clocksource; |
| 123 | static struct clocksource *next_clocksource; | ||
| 124 | static LIST_HEAD(clocksource_list); | 120 | static LIST_HEAD(clocksource_list); |
| 125 | static DEFINE_SPINLOCK(clocksource_lock); | 121 | static DEFINE_MUTEX(clocksource_mutex); |
| 126 | static char override_name[32]; | 122 | static char override_name[32]; |
| 127 | static int finished_booting; | ||
| 128 | |||
| 129 | /* clocksource_done_booting - Called near the end of core bootup | ||
| 130 | * | ||
| 131 | * Hack to avoid lots of clocksource churn at boot time. | ||
| 132 | * We use fs_initcall because we want this to start before | ||
| 133 | * device_initcall but after subsys_initcall. | ||
| 134 | */ | ||
| 135 | static int __init clocksource_done_booting(void) | ||
| 136 | { | ||
| 137 | finished_booting = 1; | ||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | fs_initcall(clocksource_done_booting); | ||
| 141 | 123 | ||
| 142 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG | 124 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG |
| 143 | static LIST_HEAD(watchdog_list); | 125 | static LIST_HEAD(watchdog_list); |
| @@ -356,18 +338,16 @@ static inline void clocksource_resume_watchdog(void) { } | |||
| 356 | void clocksource_resume(void) | 338 | void clocksource_resume(void) |
| 357 | { | 339 | { |
| 358 | struct clocksource *cs; | 340 | struct clocksource *cs; |
| 359 | unsigned long flags; | ||
| 360 | 341 | ||
| 361 | spin_lock_irqsave(&clocksource_lock, flags); | 342 | mutex_lock(&clocksource_mutex); |
| 362 | 343 | ||
| 363 | list_for_each_entry(cs, &clocksource_list, list) { | 344 | list_for_each_entry(cs, &clocksource_list, list) |
| 364 | if (cs->resume) | 345 | if (cs->resume) |
| 365 | cs->resume(); | 346 | cs->resume(); |
| 366 | } | ||
| 367 | 347 | ||
| 368 | clocksource_resume_watchdog(); | 348 | clocksource_resume_watchdog(); |
| 369 | 349 | ||
| 370 | spin_unlock_irqrestore(&clocksource_lock, flags); | 350 | mutex_unlock(&clocksource_mutex); |
| 371 | } | 351 | } |
| 372 | 352 | ||
| 373 | /** | 353 | /** |
| @@ -383,28 +363,13 @@ void clocksource_touch_watchdog(void) | |||
| 383 | } | 363 | } |
| 384 | 364 | ||
| 385 | #ifdef CONFIG_GENERIC_TIME | 365 | #ifdef CONFIG_GENERIC_TIME |
| 386 | /** | ||
| 387 | * clocksource_get_next - Returns the selected clocksource | ||
| 388 | * | ||
| 389 | */ | ||
| 390 | struct clocksource *clocksource_get_next(void) | ||
| 391 | { | ||
| 392 | unsigned long flags; | ||
| 393 | 366 | ||
| 394 | spin_lock_irqsave(&clocksource_lock, flags); | 367 | static int finished_booting; |
| 395 | if (next_clocksource && finished_booting) { | ||
| 396 | curr_clocksource = next_clocksource; | ||
| 397 | next_clocksource = NULL; | ||
| 398 | } | ||
| 399 | spin_unlock_irqrestore(&clocksource_lock, flags); | ||
| 400 | |||
| 401 | return curr_clocksource; | ||
| 402 | } | ||
| 403 | 368 | ||
| 404 | /** | 369 | /** |
| 405 | * clocksource_select - Select the best clocksource available | 370 | * clocksource_select - Select the best clocksource available |
| 406 | * | 371 | * |
| 407 | * Private function. Must hold clocksource_lock when called. | 372 | * Private function. Must hold clocksource_mutex when called. |
| 408 | * | 373 | * |
| 409 | * Select the clocksource with the best rating, or the clocksource, | 374 | * Select the clocksource with the best rating, or the clocksource, |
| 410 | * which is selected by userspace override. | 375 | * which is selected by userspace override. |
| @@ -413,7 +378,7 @@ static void clocksource_select(void) | |||
| 413 | { | 378 | { |
| 414 | struct clocksource *best, *cs; | 379 | struct clocksource *best, *cs; |
| 415 | 380 | ||
| 416 | if (list_empty(&clocksource_list)) | 381 | if (!finished_booting || list_empty(&clocksource_list)) |
| 417 | return; | 382 | return; |
| 418 | /* First clocksource on the list has the best rating. */ | 383 | /* First clocksource on the list has the best rating. */ |
| 419 | best = list_first_entry(&clocksource_list, struct clocksource, list); | 384 | best = list_first_entry(&clocksource_list, struct clocksource, list); |
| @@ -438,13 +403,31 @@ static void clocksource_select(void) | |||
| 438 | best = cs; | 403 | best = cs; |
| 439 | break; | 404 | break; |
| 440 | } | 405 | } |
| 441 | if (curr_clocksource != best) | 406 | if (curr_clocksource != best) { |
| 442 | next_clocksource = best; | 407 | printk(KERN_INFO "Switching to clocksource %s\n", best->name); |
| 408 | curr_clocksource = best; | ||
| 409 | timekeeping_notify(curr_clocksource); | ||
| 410 | } | ||
| 443 | } | 411 | } |
| 444 | 412 | ||
| 413 | /* | ||
| 414 | * clocksource_done_booting - Called near the end of core bootup | ||
| 415 | * | ||
| 416 | * Hack to avoid lots of clocksource churn at boot time. | ||
| 417 | * We use fs_initcall because we want this to start before | ||
| 418 | * device_initcall but after subsys_initcall. | ||
| 419 | */ | ||
| 420 | static int __init clocksource_done_booting(void) | ||
| 421 | { | ||
| 422 | finished_booting = 1; | ||
| 423 | clocksource_select(); | ||
| 424 | return 0; | ||
| 425 | } | ||
| 426 | fs_initcall(clocksource_done_booting); | ||
| 427 | |||
| 445 | #else /* CONFIG_GENERIC_TIME */ | 428 | #else /* CONFIG_GENERIC_TIME */ |
| 446 | 429 | ||
| 447 | static void clocksource_select(void) { } | 430 | static inline void clocksource_select(void) { } |
| 448 | 431 | ||
| 449 | #endif | 432 | #endif |
| 450 | 433 | ||
| @@ -471,13 +454,11 @@ static void clocksource_enqueue(struct clocksource *cs) | |||
| 471 | */ | 454 | */ |
| 472 | int clocksource_register(struct clocksource *cs) | 455 | int clocksource_register(struct clocksource *cs) |
| 473 | { | 456 | { |
| 474 | unsigned long flags; | 457 | mutex_lock(&clocksource_mutex); |
| 475 | |||
| 476 | spin_lock_irqsave(&clocksource_lock, flags); | ||
| 477 | clocksource_enqueue(cs); | 458 | clocksource_enqueue(cs); |
| 478 | clocksource_select(); | 459 | clocksource_select(); |
| 479 | spin_unlock_irqrestore(&clocksource_lock, flags); | ||
| 480 | clocksource_enqueue_watchdog(cs); | 460 | clocksource_enqueue_watchdog(cs); |
| 461 | mutex_unlock(&clocksource_mutex); | ||
| 481 | return 0; | 462 | return 0; |
| 482 | } | 463 | } |
| 483 | EXPORT_SYMBOL(clocksource_register); | 464 | EXPORT_SYMBOL(clocksource_register); |
| @@ -487,14 +468,12 @@ EXPORT_SYMBOL(clocksource_register); | |||
| 487 | */ | 468 | */ |
| 488 | void clocksource_change_rating(struct clocksource *cs, int rating) | 469 | void clocksource_change_rating(struct clocksource *cs, int rating) |
| 489 | { | 470 | { |
| 490 | unsigned long flags; | 471 | mutex_lock(&clocksource_mutex); |
| 491 | |||
| 492 | spin_lock_irqsave(&clocksource_lock, flags); | ||
| 493 | list_del(&cs->list); | 472 | list_del(&cs->list); |
| 494 | cs->rating = rating; | 473 | cs->rating = rating; |
| 495 | clocksource_enqueue(cs); | 474 | clocksource_enqueue(cs); |
| 496 | clocksource_select(); | 475 | clocksource_select(); |
| 497 | spin_unlock_irqrestore(&clocksource_lock, flags); | 476 | mutex_unlock(&clocksource_mutex); |
| 498 | } | 477 | } |
| 499 | EXPORT_SYMBOL(clocksource_change_rating); | 478 | EXPORT_SYMBOL(clocksource_change_rating); |
| 500 | 479 | ||
| @@ -503,13 +482,11 @@ EXPORT_SYMBOL(clocksource_change_rating); | |||
| 503 | */ | 482 | */ |
| 504 | void clocksource_unregister(struct clocksource *cs) | 483 | void clocksource_unregister(struct clocksource *cs) |
| 505 | { | 484 | { |
| 506 | unsigned long flags; | 485 | mutex_lock(&clocksource_mutex); |
| 507 | |||
| 508 | clocksource_dequeue_watchdog(cs); | 486 | clocksource_dequeue_watchdog(cs); |
| 509 | spin_lock_irqsave(&clocksource_lock, flags); | ||
| 510 | list_del(&cs->list); | 487 | list_del(&cs->list); |
| 511 | clocksource_select(); | 488 | clocksource_select(); |
| 512 | spin_unlock_irqrestore(&clocksource_lock, flags); | 489 | mutex_unlock(&clocksource_mutex); |
| 513 | } | 490 | } |
| 514 | EXPORT_SYMBOL(clocksource_unregister); | 491 | EXPORT_SYMBOL(clocksource_unregister); |
| 515 | 492 | ||
| @@ -527,9 +504,9 @@ sysfs_show_current_clocksources(struct sys_device *dev, | |||
| 527 | { | 504 | { |
| 528 | ssize_t count = 0; | 505 | ssize_t count = 0; |
| 529 | 506 | ||
| 530 | spin_lock_irq(&clocksource_lock); | 507 | mutex_lock(&clocksource_mutex); |
| 531 | count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name); | 508 | count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name); |
| 532 | spin_unlock_irq(&clocksource_lock); | 509 | mutex_unlock(&clocksource_mutex); |
| 533 | 510 | ||
| 534 | return count; | 511 | return count; |
| 535 | } | 512 | } |
| @@ -557,14 +534,14 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, | |||
| 557 | if (buf[count-1] == '\n') | 534 | if (buf[count-1] == '\n') |
| 558 | count--; | 535 | count--; |
| 559 | 536 | ||
| 560 | spin_lock_irq(&clocksource_lock); | 537 | mutex_lock(&clocksource_mutex); |
| 561 | 538 | ||
| 562 | if (count > 0) | 539 | if (count > 0) |
| 563 | memcpy(override_name, buf, count); | 540 | memcpy(override_name, buf, count); |
| 564 | override_name[count] = 0; | 541 | override_name[count] = 0; |
| 565 | clocksource_select(); | 542 | clocksource_select(); |
| 566 | 543 | ||
| 567 | spin_unlock_irq(&clocksource_lock); | 544 | mutex_unlock(&clocksource_mutex); |
| 568 | 545 | ||
| 569 | return ret; | 546 | return ret; |
| 570 | } | 547 | } |
| @@ -584,7 +561,7 @@ sysfs_show_available_clocksources(struct sys_device *dev, | |||
| 584 | struct clocksource *src; | 561 | struct clocksource *src; |
| 585 | ssize_t count = 0; | 562 | ssize_t count = 0; |
| 586 | 563 | ||
| 587 | spin_lock_irq(&clocksource_lock); | 564 | mutex_lock(&clocksource_mutex); |
| 588 | list_for_each_entry(src, &clocksource_list, list) { | 565 | list_for_each_entry(src, &clocksource_list, list) { |
| 589 | /* | 566 | /* |
| 590 | * Don't show non-HRES clocksource if the tick code is | 567 | * Don't show non-HRES clocksource if the tick code is |
| @@ -596,7 +573,7 @@ sysfs_show_available_clocksources(struct sys_device *dev, | |||
| 596 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), | 573 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), |
| 597 | "%s ", src->name); | 574 | "%s ", src->name); |
| 598 | } | 575 | } |
| 599 | spin_unlock_irq(&clocksource_lock); | 576 | mutex_unlock(&clocksource_mutex); |
| 600 | 577 | ||
| 601 | count += snprintf(buf + count, | 578 | count += snprintf(buf + count, |
| 602 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n"); | 579 | max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n"); |
| @@ -651,11 +628,10 @@ device_initcall(init_clocksource_sysfs); | |||
| 651 | */ | 628 | */ |
| 652 | static int __init boot_override_clocksource(char* str) | 629 | static int __init boot_override_clocksource(char* str) |
| 653 | { | 630 | { |
| 654 | unsigned long flags; | 631 | mutex_lock(&clocksource_mutex); |
| 655 | spin_lock_irqsave(&clocksource_lock, flags); | ||
| 656 | if (str) | 632 | if (str) |
| 657 | strlcpy(override_name, str, sizeof(override_name)); | 633 | strlcpy(override_name, str, sizeof(override_name)); |
| 658 | spin_unlock_irqrestore(&clocksource_lock, flags); | 634 | mutex_unlock(&clocksource_mutex); |
| 659 | return 1; | 635 | return 1; |
| 660 | } | 636 | } |
| 661 | 637 | ||
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 27ae01b596b7..41579e7fcf9d 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/jiffies.h> | 18 | #include <linux/jiffies.h> |
| 19 | #include <linux/time.h> | 19 | #include <linux/time.h> |
| 20 | #include <linux/tick.h> | 20 | #include <linux/tick.h> |
| 21 | #include <linux/stop_machine.h> | ||
| 21 | 22 | ||
| 22 | /* Structure holding internal timekeeping values. */ | 23 | /* Structure holding internal timekeeping values. */ |
| 23 | struct timekeeper { | 24 | struct timekeeper { |
| @@ -179,6 +180,7 @@ void timekeeping_leap_insert(int leapsecond) | |||
| 179 | } | 180 | } |
| 180 | 181 | ||
| 181 | #ifdef CONFIG_GENERIC_TIME | 182 | #ifdef CONFIG_GENERIC_TIME |
| 183 | |||
| 182 | /** | 184 | /** |
| 183 | * timekeeping_forward_now - update clock to the current time | 185 | * timekeeping_forward_now - update clock to the current time |
| 184 | * | 186 | * |
| @@ -351,31 +353,40 @@ EXPORT_SYMBOL(do_settimeofday); | |||
| 351 | * | 353 | * |
| 352 | * Accumulates current time interval and initializes new clocksource | 354 | * Accumulates current time interval and initializes new clocksource |
| 353 | */ | 355 | */ |
| 354 | static void change_clocksource(void) | 356 | static int change_clocksource(void *data) |
| 355 | { | 357 | { |
| 356 | struct clocksource *new, *old; | 358 | struct clocksource *new, *old; |
| 357 | 359 | ||
| 358 | new = clocksource_get_next(); | 360 | new = (struct clocksource *) data; |
| 359 | |||
| 360 | if (!new || timekeeper.clock == new) | ||
| 361 | return; | ||
| 362 | 361 | ||
| 363 | timekeeping_forward_now(); | 362 | timekeeping_forward_now(); |
| 363 | if (!new->enable || new->enable(new) == 0) { | ||
| 364 | old = timekeeper.clock; | ||
| 365 | timekeeper_setup_internals(new); | ||
| 366 | if (old->disable) | ||
| 367 | old->disable(old); | ||
| 368 | } | ||
| 369 | return 0; | ||
| 370 | } | ||
| 364 | 371 | ||
| 365 | if (new->enable && !new->enable(new)) | 372 | /** |
| 373 | * timekeeping_notify - Install a new clock source | ||
| 374 | * @clock: pointer to the clock source | ||
| 375 | * | ||
| 376 | * This function is called from clocksource.c after a new, better clock | ||
| 377 | * source has been registered. The caller holds the clocksource_mutex. | ||
| 378 | */ | ||
| 379 | void timekeeping_notify(struct clocksource *clock) | ||
| 380 | { | ||
| 381 | if (timekeeper.clock == clock) | ||
| 366 | return; | 382 | return; |
| 367 | 383 | stop_machine(change_clocksource, clock, NULL); | |
| 368 | old = timekeeper.clock; | ||
| 369 | timekeeper_setup_internals(new); | ||
| 370 | |||
| 371 | if (old->disable) | ||
| 372 | old->disable(old); | ||
| 373 | |||
| 374 | tick_clock_notify(); | 384 | tick_clock_notify(); |
| 375 | } | 385 | } |
| 386 | |||
| 376 | #else /* GENERIC_TIME */ | 387 | #else /* GENERIC_TIME */ |
| 388 | |||
| 377 | static inline void timekeeping_forward_now(void) { } | 389 | static inline void timekeeping_forward_now(void) { } |
| 378 | static inline void change_clocksource(void) { } | ||
| 379 | 390 | ||
| 380 | /** | 391 | /** |
| 381 | * ktime_get - get the monotonic time in ktime_t format | 392 | * ktime_get - get the monotonic time in ktime_t format |
| @@ -416,6 +427,7 @@ void ktime_get_ts(struct timespec *ts) | |||
| 416 | ts->tv_nsec + tomono.tv_nsec); | 427 | ts->tv_nsec + tomono.tv_nsec); |
| 417 | } | 428 | } |
| 418 | EXPORT_SYMBOL_GPL(ktime_get_ts); | 429 | EXPORT_SYMBOL_GPL(ktime_get_ts); |
| 430 | |||
| 419 | #endif /* !GENERIC_TIME */ | 431 | #endif /* !GENERIC_TIME */ |
| 420 | 432 | ||
| 421 | /** | 433 | /** |
| @@ -773,7 +785,6 @@ void update_wall_time(void) | |||
| 773 | update_xtime_cache(nsecs); | 785 | update_xtime_cache(nsecs); |
| 774 | 786 | ||
| 775 | /* check to see if there is a new clocksource to use */ | 787 | /* check to see if there is a new clocksource to use */ |
| 776 | change_clocksource(); | ||
| 777 | update_vsyscall(&xtime, timekeeper.clock); | 788 | update_vsyscall(&xtime, timekeeper.clock); |
| 778 | } | 789 | } |
| 779 | 790 | ||
