diff options
| author | Marc Zyngier <marc.zyngier@arm.com> | 2017-02-01 07:07:15 -0500 |
|---|---|---|
| committer | Marc Zyngier <marc.zyngier@arm.com> | 2017-04-07 06:22:09 -0400 |
| commit | a86bd139f2ae02f960caeb0c1dd5f871d3e087cd (patch) | |
| tree | 63271d9e67e1cb7ac7e5784052d815355d750061 /drivers/clocksource | |
| parent | bee67c53a990452c4f3c7a0e9cebfecb5acfbde3 (diff) | |
arm64: arch_timer: Enable CNTVCT_EL0 trap if workaround is enabled
Userspace being allowed to use read CNTVCT_EL0 anytime (and not
only in the VDSO), we need to enable trapping whenever a cntvct
workaround is enabled on a given CPU.
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 45 |
1 files changed, 32 insertions, 13 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5c114da0ed71..f8adea258cf0 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
| @@ -83,6 +83,7 @@ static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI; | |||
| 83 | static bool arch_timer_c3stop; | 83 | static bool arch_timer_c3stop; |
| 84 | static bool arch_timer_mem_use_virtual; | 84 | static bool arch_timer_mem_use_virtual; |
| 85 | static bool arch_counter_suspend_stop; | 85 | static bool arch_counter_suspend_stop; |
| 86 | static bool vdso_default = true; | ||
| 86 | 87 | ||
| 87 | static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); | 88 | static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); |
| 88 | 89 | ||
| @@ -383,6 +384,17 @@ void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa | |||
| 383 | } | 384 | } |
| 384 | 385 | ||
| 385 | static_branch_enable(&arch_timer_read_ool_enabled); | 386 | static_branch_enable(&arch_timer_read_ool_enabled); |
| 387 | |||
| 388 | /* | ||
| 389 | * Don't use the vdso fastpath if errata require using the | ||
| 390 | * out-of-line counter accessor. We may change our mind pretty | ||
| 391 | * late in the game (with a per-CPU erratum, for example), so | ||
| 392 | * change both the default value and the vdso itself. | ||
| 393 | */ | ||
| 394 | if (wa->read_cntvct_el0) { | ||
| 395 | clocksource_counter.archdata.vdso_direct = false; | ||
| 396 | vdso_default = false; | ||
| 397 | } | ||
| 386 | } | 398 | } |
| 387 | 399 | ||
| 388 | static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type type, | 400 | static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type type, |
| @@ -443,11 +455,19 @@ static void arch_timer_check_ool_workaround(enum arch_timer_erratum_match_type t | |||
| 443 | __val; \ | 455 | __val; \ |
| 444 | }) | 456 | }) |
| 445 | 457 | ||
| 458 | static bool arch_timer_this_cpu_has_cntvct_wa(void) | ||
| 459 | { | ||
| 460 | const struct arch_timer_erratum_workaround *wa; | ||
| 461 | |||
| 462 | wa = __this_cpu_read(timer_unstable_counter_workaround); | ||
| 463 | return wa && wa->read_cntvct_el0; | ||
| 464 | } | ||
| 446 | #else | 465 | #else |
| 447 | #define arch_timer_check_ool_workaround(t,a) do { } while(0) | 466 | #define arch_timer_check_ool_workaround(t,a) do { } while(0) |
| 448 | #define erratum_set_next_event_tval_virt(...) ({BUG(); 0;}) | 467 | #define erratum_set_next_event_tval_virt(...) ({BUG(); 0;}) |
| 449 | #define erratum_set_next_event_tval_phys(...) ({BUG(); 0;}) | 468 | #define erratum_set_next_event_tval_phys(...) ({BUG(); 0;}) |
| 450 | #define erratum_handler(fn, r, ...) ({false;}) | 469 | #define erratum_handler(fn, r, ...) ({false;}) |
| 470 | #define arch_timer_this_cpu_has_cntvct_wa() ({false;}) | ||
| 451 | #endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ | 471 | #endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ |
| 452 | 472 | ||
| 453 | static __always_inline irqreturn_t timer_handler(const int access, | 473 | static __always_inline irqreturn_t timer_handler(const int access, |
| @@ -660,15 +680,23 @@ static void arch_counter_set_user_access(void) | |||
| 660 | { | 680 | { |
| 661 | u32 cntkctl = arch_timer_get_cntkctl(); | 681 | u32 cntkctl = arch_timer_get_cntkctl(); |
| 662 | 682 | ||
| 663 | /* Disable user access to the timers and the physical counter */ | 683 | /* Disable user access to the timers and both counters */ |
| 664 | /* Also disable virtual event stream */ | 684 | /* Also disable virtual event stream */ |
| 665 | cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN | 685 | cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN |
| 666 | | ARCH_TIMER_USR_VT_ACCESS_EN | 686 | | ARCH_TIMER_USR_VT_ACCESS_EN |
| 687 | | ARCH_TIMER_USR_VCT_ACCESS_EN | ||
| 667 | | ARCH_TIMER_VIRT_EVT_EN | 688 | | ARCH_TIMER_VIRT_EVT_EN |
| 668 | | ARCH_TIMER_USR_PCT_ACCESS_EN); | 689 | | ARCH_TIMER_USR_PCT_ACCESS_EN); |
| 669 | 690 | ||
| 670 | /* Enable user access to the virtual counter */ | 691 | /* |
| 671 | cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; | 692 | * Enable user access to the virtual counter if it doesn't |
| 693 | * need to be workaround. The vdso may have been already | ||
| 694 | * disabled though. | ||
| 695 | */ | ||
| 696 | if (arch_timer_this_cpu_has_cntvct_wa()) | ||
| 697 | pr_info("CPU%d: Trapping CNTVCT access\n", smp_processor_id()); | ||
| 698 | else | ||
| 699 | cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; | ||
| 672 | 700 | ||
| 673 | arch_timer_set_cntkctl(cntkctl); | 701 | arch_timer_set_cntkctl(cntkctl); |
| 674 | } | 702 | } |
| @@ -791,16 +819,7 @@ static void __init arch_counter_register(unsigned type) | |||
| 791 | else | 819 | else |
| 792 | arch_timer_read_counter = arch_counter_get_cntpct; | 820 | arch_timer_read_counter = arch_counter_get_cntpct; |
| 793 | 821 | ||
| 794 | clocksource_counter.archdata.vdso_direct = true; | 822 | clocksource_counter.archdata.vdso_direct = vdso_default; |
| 795 | |||
| 796 | #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND | ||
| 797 | /* | ||
| 798 | * Don't use the vdso fastpath if errata require using | ||
| 799 | * the out-of-line counter accessor. | ||
| 800 | */ | ||
| 801 | if (static_branch_unlikely(&arch_timer_read_ool_enabled)) | ||
| 802 | clocksource_counter.archdata.vdso_direct = false; | ||
| 803 | #endif | ||
| 804 | } else { | 823 | } else { |
| 805 | arch_timer_read_counter = arch_counter_get_cntvct_mem; | 824 | arch_timer_read_counter = arch_counter_get_cntvct_mem; |
| 806 | } | 825 | } |
