Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / clocksource / arm_arch_timer.c
index 5163ec1..2133f9d 100644 (file)
@@ -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,19 @@ 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)
+       if (type & ARCH_CP15_TIMER) {
                arch_timer_read_counter = arch_counter_get_cntvct;
-       else
+       } 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 +656,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 = false;
+
+       dn = of_find_matching_node(NULL, matches);
+       if (dn && of_device_is_available(dn) && (arch_timers_present & type))
+               probed = true;
+       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;
        }