Skip to content

Commit

Permalink
clocksource/drivers/arm_arch_timer: Initialize evtstrm after finalizi…
Browse files Browse the repository at this point in the history
…ng cpucaps

We attempt to initialize each CPU's arch_timer event stream in
arch_timer_evtstrm_enable(), which we call from the
arch_timer_starting_cpu() cpu hotplug callback which is registered early
in boot. As this is registered before we initialize the system cpucaps,
the test for ARM64_HAS_ECV will always be false for CPUs present at boot
time, and will only be taken into account for CPUs onlined late
(including those which are hotplugged out and in again).

Due to this, CPUs present and boot time may not use the intended divider
and scale factor to generate the event stream, and may differ from other
CPUs.

Correct this by only initializing the event stream after cpucaps have been
finalized, registering a separate CPU hotplug callback for the event stream
configuration. Since the caps must be finalized by this point, use
cpus_have_final_cap() to verify this.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
  • Loading branch information
Mark Rutland authored and Catalin Marinas committed Oct 16, 2023
1 parent 6465e26 commit 166b76a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 5 deletions.
31 changes: 26 additions & 5 deletions drivers/clocksource/arm_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ static void arch_timer_evtstrm_enable(unsigned int divider)

#ifdef CONFIG_ARM64
/* ECV is likely to require a large divider. Use the EVNTIS flag. */
if (cpus_have_const_cap(ARM64_HAS_ECV) && divider > 15) {
if (cpus_have_final_cap(ARM64_HAS_ECV) && divider > 15) {
cntkctl |= ARCH_TIMER_EVT_INTERVAL_SCALE;
divider -= 8;
}
Expand Down Expand Up @@ -955,6 +955,30 @@ static void arch_timer_configure_evtstream(void)
arch_timer_evtstrm_enable(max(0, lsb));
}

static int arch_timer_evtstrm_starting_cpu(unsigned int cpu)
{
arch_timer_configure_evtstream();
return 0;
}

static int arch_timer_evtstrm_dying_cpu(unsigned int cpu)
{
cpumask_clear_cpu(smp_processor_id(), &evtstrm_available);
return 0;
}

static int __init arch_timer_evtstrm_register(void)
{
if (!arch_timer_evt || !evtstrm_enable)
return 0;

return cpuhp_setup_state(CPUHP_AP_ARM_ARCH_TIMER_EVTSTRM_STARTING,
"clockevents/arm/arch_timer_evtstrm:starting",
arch_timer_evtstrm_starting_cpu,
arch_timer_evtstrm_dying_cpu);
}
core_initcall(arch_timer_evtstrm_register);

static void arch_counter_set_user_access(void)
{
u32 cntkctl = arch_timer_get_cntkctl();
Expand Down Expand Up @@ -1016,8 +1040,6 @@ static int arch_timer_starting_cpu(unsigned int cpu)
}

arch_counter_set_user_access();
if (evtstrm_enable)
arch_timer_configure_evtstream();

return 0;
}
Expand Down Expand Up @@ -1164,8 +1186,6 @@ static int arch_timer_dying_cpu(unsigned int cpu)
{
struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);

cpumask_clear_cpu(smp_processor_id(), &evtstrm_available);

arch_timer_stop(clk);
return 0;
}
Expand Down Expand Up @@ -1279,6 +1299,7 @@ static int __init arch_timer_register(void)

out_free:
free_percpu(arch_timer_evt);
arch_timer_evt = NULL;
out:
return err;
}
Expand Down
1 change: 1 addition & 0 deletions include/linux/cpuhotplug.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ enum cpuhp_state {
CPUHP_AP_ARM_L2X0_STARTING,
CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
CPUHP_AP_ARM_ARCH_TIMER_STARTING,
CPUHP_AP_ARM_ARCH_TIMER_EVTSTRM_STARTING,
CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
CPUHP_AP_JCORE_TIMER_STARTING,
CPUHP_AP_ARM_TWD_STARTING,
Expand Down

0 comments on commit 166b76a

Please sign in to comment.