diff options
Diffstat (limited to 'kernel/time/clocksource.c')
-rw-r--r-- | kernel/time/clocksource.c | 112 |
1 files changed, 44 insertions, 68 deletions
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 | ||