[PATCH v2] arm64: acpi/gtdt: validate CNTFRQ after having enabled the frame
Ard Biesheuvel
ard.biesheuvel at linaro.org
Thu Aug 31 07:23:33 PDT 2017
On 21 August 2017 at 10:56, Ard Biesheuvel <ard.biesheuvel at linaro.org> wrote:
> The ACPI GTDT code validates the CNTFRQ field of each MMIO timer
> frame against the CNTFRQ system register of the current CPU, to
> ensure that they are equal, which is mandated by the architecture.
>
> However, reading the CNTFRQ field of a frame is not possible until
> the RFRQ bit in the frame's CNTACRn register is set, and doing so
> before that willl produce the following error:
>
> arch_timer: [Firmware Bug]: CNTFRQ mismatch: frame @ 0x00000000e0be0000: (0x00000000), CPU: (0x0ee6b280)
> arch_timer: Disabling MMIO timers due to CNTFRQ mismatch
> arch_timer: Failed to initialize memory-mapped timer.
>
> The reason is that the CNTFRQ field is RES0 if access is not enabled.
>
> So move the validation of CNTFRQ into the loop that iterates over the
> timers to find the best frame, and disregard the frame if its CNTFRQ
> field differs from the CPU timer's CNTFRQ value. Even though the
> architecture suggests that the CNTFRQ field of each frame should simply
> reflect the CNTFRQ value of the base frame, in reality we cannot rule
> out the possibility that there is another frame available that does
> have the correct value, and so it makes sense to inspect any remaining
> frames in this case.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
Ping?
> ---
> drivers/clocksource/arm_arch_timer.c | 47 +++++++-----------------------------
> 1 file changed, 9 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
> index aae87c4c546e..c16fa694a47b 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -1217,7 +1217,8 @@ arch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame)
> }
>
> static struct arch_timer_mem_frame * __init
> -arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem)
> +arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem,
> + bool verify_freq)
> {
> struct arch_timer_mem_frame *frame, *best_frame = NULL;
> void __iomem *cntctlbase;
> @@ -1259,6 +1260,11 @@ arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem)
> if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
> continue;
>
> + if (verify_freq &&
> + arch_timer_mem_frame_get_cntfrq(frame) != arch_timer_rate) {
> + pr_err(FW_BUG "Ignoring MMIO timer frame with incorrect CNTFRQ\n");
> + continue;
> + }
> best_frame = frame;
> }
>
> @@ -1366,7 +1372,7 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
> frame->valid = true;
> }
>
> - frame = arch_timer_mem_find_best_frame(timer_mem);
> + frame = arch_timer_mem_find_best_frame(timer_mem, false);
> if (!frame) {
> ret = -EINVAL;
> goto out;
> @@ -1386,33 +1392,6 @@ TIMER_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
> arch_timer_mem_of_init);
>
> #ifdef CONFIG_ACPI_GTDT
> -static int __init
> -arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem)
> -{
> - struct arch_timer_mem_frame *frame;
> - u32 rate;
> - int i;
> -
> - for (i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) {
> - frame = &timer_mem->frame[i];
> -
> - if (!frame->valid)
> - continue;
> -
> - rate = arch_timer_mem_frame_get_cntfrq(frame);
> - if (rate == arch_timer_rate)
> - continue;
> -
> - pr_err(FW_BUG "CNTFRQ mismatch: frame @ %pa: (0x%08lx), CPU: (0x%08lx)\n",
> - &frame->cntbase,
> - (unsigned long)rate, (unsigned long)arch_timer_rate);
> -
> - return -EINVAL;
> - }
> -
> - return 0;
> -}
> -
> static int __init arch_timer_mem_acpi_init(int platform_timer_count)
> {
> struct arch_timer_mem *timers, *timer;
> @@ -1428,14 +1407,6 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
> if (ret || !timer_count)
> goto out;
>
> - for (i = 0; i < timer_count; i++) {
> - ret = arch_timer_mem_verify_cntfrq(&timers[i]);
> - if (ret) {
> - pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n");
> - goto out;
> - }
> - }
> -
> /*
> * While unlikely, it's theoretically possible that none of the frames
> * in a timer expose the combination of feature we want.
> @@ -1443,7 +1414,7 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
> for (i = i; i < timer_count; i++) {
> timer = &timers[i];
>
> - frame = arch_timer_mem_find_best_frame(timer);
> + frame = arch_timer_mem_find_best_frame(timer, true);
> if (frame)
> break;
> }
> --
> 2.11.0
>
More information about the linux-arm-kernel
mailing list