[PATCH v3] arm64: acpi/gtdt: validate CNTFRQ after having enabled the frame

Ard Biesheuvel ard.biesheuvel at linaro.org
Mon Oct 2 07:12:17 PDT 2017


On 1 September 2017 at 11:35, 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, but defer it until after we have selected
> the best frame, which should also have enabled the RFRQ bit.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
> ---
> v3: - preserve existing logic as much as possible wrt verifying all frames of
>       all timers before selecting a suitable one
>

Ping?


>  drivers/clocksource/arm_arch_timer.c | 38 +++++++++++---------
>  1 file changed, 21 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
> index 72bbfccef113..30071cdea846 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -1264,10 +1264,6 @@ arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem)
>
>         iounmap(cntctlbase);
>
> -       if (!best_frame)
> -               pr_err("Unable to find a suitable frame in timer @ %pa\n",
> -                       &timer_mem->cntctlbase);
> -
>         return best_frame;
>  }
>
> @@ -1368,6 +1364,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np)
>
>         frame = arch_timer_mem_find_best_frame(timer_mem);
>         if (!frame) {
> +               pr_err("Unable to find a suitable frame in timer @ %pa\n",
> +                       &timer_mem->cntctlbase);
>                 ret = -EINVAL;
>                 goto out;
>         }
> @@ -1416,7 +1414,7 @@ arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem)
>  static int __init arch_timer_mem_acpi_init(int platform_timer_count)
>  {
>         struct arch_timer_mem *timers, *timer;
> -       struct arch_timer_mem_frame *frame;
> +       struct arch_timer_mem_frame *frame, *best_frame = NULL;
>         int timer_count, i, ret = 0;
>
>         timers = kcalloc(platform_timer_count, sizeof(*timers),
> @@ -1428,14 +1426,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.
> @@ -1444,12 +1434,26 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
>                 timer = &timers[i];
>
>                 frame = arch_timer_mem_find_best_frame(timer);
> -               if (frame)
> -                       break;
> +               if (!best_frame)
> +                       best_frame = frame;
> +
> +               ret = arch_timer_mem_verify_cntfrq(timer);
> +               if (ret) {
> +                       pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n");
> +                       goto out;
> +               }
> +
> +               if (!best_frame) /* implies !frame */
> +                       /*
> +                        * Only complain about missing suitable frames if we
> +                        * haven't already found one in a previous iteration.
> +                        */
> +                       pr_err("Unable to find a suitable frame in timer @ %pa\n",
> +                               &timer->cntctlbase);
>         }
>
> -       if (frame)
> -               ret = arch_timer_mem_frame_register(frame);
> +       if (best_frame)
> +               ret = arch_timer_mem_frame_register(best_frame);
>  out:
>         kfree(timers);
>         return ret;
> --
> 2.11.0
>



More information about the linux-arm-kernel mailing list