diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 11:35:36 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 11:35:36 -0800 |
commit | 4ba24fef3eb3b142197135223b90ced2f319cd53 (patch) | |
tree | a20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/clocksource/arm_arch_timer.c | |
parent | 47c1ffb2b6b630894e9a16442611c056ab21c057 (diff) | |
parent | 98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (diff) |
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.20.
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 77 |
1 files changed, 70 insertions, 7 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 5163ec13429..095c1774592 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -299,6 +299,21 @@ static void __arch_timer_setup(unsigned type, clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); } +static void arch_timer_evtstrm_enable(int divider) +{ + u32 cntkctl = arch_timer_get_cntkctl(); + + cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK; + /* Set the divider and enable virtual event stream */ + cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) + | ARCH_TIMER_VIRT_EVT_EN; + arch_timer_set_cntkctl(cntkctl); + elf_hwcap |= HWCAP_EVTSTRM; +#ifdef CONFIG_COMPAT + compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; +#endif +} + static void arch_timer_configure_evtstream(void) { int evt_stream_div, pos; @@ -312,6 +327,23 @@ static void arch_timer_configure_evtstream(void) arch_timer_evtstrm_enable(min(pos, 15)); } +static void arch_counter_set_user_access(void) +{ + u32 cntkctl = arch_timer_get_cntkctl(); + + /* Disable user access to the timers and the physical counter */ + /* Also disable virtual event stream */ + cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN + | ARCH_TIMER_USR_VT_ACCESS_EN + | ARCH_TIMER_VIRT_EVT_EN + | ARCH_TIMER_USR_PCT_ACCESS_EN); + + /* Enable user access to the virtual counter */ + cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; + + arch_timer_set_cntkctl(cntkctl); +} + static int arch_timer_setup(struct clock_event_device *clk) { __arch_timer_setup(ARCH_CP15_TIMER, clk); @@ -429,11 +461,22 @@ static void __init arch_counter_register(unsigned type) u64 start_count; /* Register the CP15 based counter if we have one */ - if (type & ARCH_CP15_TIMER) - arch_timer_read_counter = arch_counter_get_cntvct; - else + if (type & ARCH_CP15_TIMER) { + if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual) + arch_timer_read_counter = arch_counter_get_cntvct; + else + arch_timer_read_counter = arch_counter_get_cntpct; + } else { arch_timer_read_counter = arch_counter_get_cntvct_mem; + /* If the clocksource name is "arch_sys_counter" the + * VDSO will attempt to read the CP15-based counter. + * Ensure this does not happen when CP15-based + * counter is not available. + */ + clocksource_counter.name = "arch_mem_counter"; + } + start_count = arch_timer_read_counter(); clocksource_register_hz(&clocksource_counter, arch_timer_rate); cyclecounter.mult = clocksource_counter.mult; @@ -616,17 +659,29 @@ static const struct of_device_id arch_timer_mem_of_match[] __initconst = { {}, }; +static bool __init +arch_timer_probed(int type, const struct of_device_id *matches) +{ + struct device_node *dn; + bool probed = true; + + dn = of_find_matching_node(NULL, matches); + if (dn && of_device_is_available(dn) && !(arch_timers_present & type)) + probed = false; + of_node_put(dn); + + return probed; +} + static void __init arch_timer_common_init(void) { unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER; /* Wait until both nodes are probed if we have two timers */ if ((arch_timers_present & mask) != mask) { - if (of_find_matching_node(NULL, arch_timer_mem_of_match) && - !(arch_timers_present & ARCH_MEM_TIMER)) + if (!arch_timer_probed(ARCH_MEM_TIMER, arch_timer_mem_of_match)) return; - if (of_find_matching_node(NULL, arch_timer_of_match) && - !(arch_timers_present & ARCH_CP15_TIMER)) + if (!arch_timer_probed(ARCH_CP15_TIMER, arch_timer_of_match)) return; } @@ -650,6 +705,14 @@ static void __init arch_timer_init(struct device_node *np) arch_timer_detect_rate(NULL, np); /* + * If we cannot rely on firmware initializing the timer registers then + * we should use the physical timers instead. + */ + if (IS_ENABLED(CONFIG_ARM) && + of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) + arch_timer_use_virtual = false; + + /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so * that a guest can use the virtual timer instead. |